jwtauth

package module
v3.0.2+incompatible Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 13, 2017 License: MIT Imports: 7 Imported by: 0

README

jwtauth - JWT authentication middleware for Go HTTP services

The jwtauth http middleware package provides a simple way to verify a JWT token from a http request and send the result down the request context (context.Context).

Please note, jwtauth works with any Go http router, but resides under the go-chi group for maintenance and organization - its only 3rd party dependency is the underlying jwt library "github.com/dgrijalva/jwt-go".

This package uses the new context package in Go 1.7 stdlib and net/http#Request.Context to pass values between handler chains.

In a complete JWT-authentication flow, you'll first capture the token from a http request, decode it, verify it and then validate that its correctly signed and hasn't expired - the jwtauth.Verifier middleware handler takes care of all of that. The jwtauth.Verifier will set the context values on keys jwtauth.TokenCtxKey and jwtauth.ErrorCtxKey.

Next, it's up to an authentication handler to respond or continue processing after the jwtauth.Verifier. The jwtauth.Authenticator middleware responds with a 401 Unauthorized plain-text payload for all unverified tokens and passes the good ones through. You can also copy the Authenticator and customize it to handle invalid tokens to better fit your flow (ie. with a JSON error response body).

The Verifier will search for a JWT token in a http request, in the order:

  1. 'jwt' URI query parameter
  2. 'Authorization: BEARER T' request header
  3. Cookie 'jwt' value
  4. (optional), use jwtauth.Verify("state") for additional query/cookie parameter aliases

The first JWT string that is found as a query parameter, authorization header or cookie header is then decoded by the jwt-go library and a *jwt.Token object is set on the request context. In the case of a signature decoding error the Verifier will also set the error on the request context.

The Verifier always calls the next http handler in sequence, which can either be the generic jwtauth.Authenticator middleware or your own custom handler which checks the request context jwt token and error to prepare a custom http response.

Usage

See the full example.

package main

import (
	"fmt"
	"net/http"

	"github.com/go-chi/chi"
	"github.com/go-chi/jwtauth"
)

var tokenAuth *jwtauth.JwtAuth

func init() {
	tokenAuth = jwtauth.New("HS256", []byte("secret"), nil)

	// For debugging/example purposes, we generate and print
	// a sample jwt token with claims `user_id:123` here:
	_, tokenString, _ := tokenAuth.Encode(jwtauth.Claims{"user_id": 123})
	fmt.Printf("DEBUG: a sample jwt is %s\n\n", tokenString)
}

func main() {
	addr := ":3333"
	fmt.Printf("Starting server on %v\n", addr)
	http.ListenAndServe(addr, router())
}

func router() http.Handler {
	r := chi.NewRouter()

	// Protected routes
	r.Group(func(r chi.Router) {
		// Seek, verify and validate JWT tokens
		r.Use(jwtauth.Verifier(tokenAuth))

		// Handle valid / invalid tokens. In this example, we use
		// the provided authenticator middleware, but you can write your
		// own very easily, look at the Authenticator method in jwtauth.go
		// and tweak it, its not scary.
		r.Use(jwtauth.Authenticator)

		r.Get("/admin", func(w http.ResponseWriter, r *http.Request) {
			_, claims, _ := jwtauth.FromContext(r.Context())
			w.Write([]byte(fmt.Sprintf("protected area. hi %v", claims["user_id"])))
		})
	})

	// Public routes
	r.Group(func(r chi.Router) {
		r.Get("/", func(w http.ResponseWriter, r *http.Request) {
			w.Write([]byte("welcome anonymous"))
		})
	})

	return r
}

LICENSE

MIT

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	TokenCtxKey = &contextKey{"Token"}
	ErrorCtxKey = &contextKey{"Error"}
)
View Source
var (
	ErrUnauthorized = errors.New("jwtauth: token is unauthorized")
	ErrExpired      = errors.New("jwtauth: token is expired")
)

Functions

func Authenticator

func Authenticator(next http.Handler) http.Handler

Authenticator is a default authentication middleware to enforce access from the Verifier middleware request context values. The Authenticator sends a 401 Unauthorized response for any unverified tokens and passes the good ones through. It's just fine until you decide to write something similar and customize your client response.

func EpochNow

func EpochNow() int64

Helper function that returns the NumericDate time value used by the spec

func ExpireIn

func ExpireIn(tm time.Duration) int64

Helper function to return calculated time in the future for "exp" claim.

func IsExpired

func IsExpired(t *jwt.Token) bool

func NewContext

func NewContext(ctx context.Context, t *jwt.Token, err error) context.Context

func Verifier

func Verifier(ja *JwtAuth) func(http.Handler) http.Handler

Verifier http middleware handler will verify a JWT string from a http request.

Verifier will search for a JWT token in a http request, in the order:

  1. 'jwt' URI query parameter
  2. 'Authorization: BEARER T' request header
  3. Cookie 'jwt' value

The first JWT string that is found as a query parameter, authorization header or cookie header is then decoded by the `jwt-go` library and a *jwt.Token object is set on the request context. In the case of a signature decoding error the Verifier will also set the error on the request context.

The Verifier always calls the next http handler in sequence, which can either be the generic `jwtauth.Authenticator` middleware or your own custom handler which checks the request context jwt token and error to prepare a custom http response.

func Verify

func Verify(ja *JwtAuth, paramAliases ...string) func(http.Handler) http.Handler

func VerifyRequest

func VerifyRequest(ja *JwtAuth, r *http.Request, paramAliases ...string) (*jwt.Token, error)

Types

type Claims

type Claims map[string]interface{}

Claims is a convenience type to manage a JWT claims hash.

func FromContext

func FromContext(ctx context.Context) (*jwt.Token, Claims, error)

func (Claims) Get

func (c Claims) Get(k string) (interface{}, bool)

func (Claims) Set

func (c Claims) Set(k string, v interface{}) Claims

func (Claims) SetExpiry

func (c Claims) SetExpiry(tm time.Time) Claims

Set expiry ("exp") in the claims and return itself so it can be chained

func (Claims) SetExpiryIn

func (c Claims) SetExpiryIn(tm time.Duration) Claims

Set expiry ("exp") in the claims to some duration from the present time and return itself so it can be chained

func (Claims) SetIssuedAt

func (c Claims) SetIssuedAt(tm time.Time) Claims

Set issued at ("iat") to specified time in the claims

func (Claims) SetIssuedNow

func (c Claims) SetIssuedNow() Claims

Set issued at ("iat") to present time in the claims

func (Claims) Valid

func (c Claims) Valid() error

NOTE: as of v3.0 of jwt-go, Valid() interface method is called to verify the claims. However, the current design we test these claims in the Verifier middleware, so we skip this step.

type JwtAuth

type JwtAuth struct {
	// contains filtered or unexported fields
}

func New

func New(alg string, signKey []byte, verifyKey []byte) *JwtAuth

New creates a JwtAuth authenticator instance that provides middleware handlers and encoding/decoding functions for JWT signing.

func NewWithParser

func NewWithParser(alg string, parser *jwt.Parser, signKey []byte, verifyKey []byte) *JwtAuth

NewWithParser is the same as New, except it supports custom parser settings introduced in jwt-go/v2.4.0.

We explicitly toggle `SkipClaimsValidation` in the `jwt-go` parser so that we can control when the claims are validated - in our case, by the Verifier http middleware handler.

func (*JwtAuth) Decode

func (ja *JwtAuth) Decode(tokenString string) (t *jwt.Token, err error)

func (*JwtAuth) Encode

func (ja *JwtAuth) Encode(claims Claims) (t *jwt.Token, tokenString string, err error)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL