2016-08-04 10:26:57 -04:00
jwtauth - JWT middleware for Go 1.7+ HTTP services
==================================================
2016-01-22 13:41:30 -05:00
2017-07-05 17:05:27 -04:00
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` ).
2016-01-22 13:41:30 -05:00
2017-07-05 17:05:27 -04:00
This package uses the new `context` package in Go 1.7 stdlib and [net/http#Request.Context ](https://golang.org/pkg/net/http/#Request.Context ) to pass values between handler chains.
2016-09-13 11:34:21 -04:00
2017-07-05 17:05:27 -04:00
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` .
2016-08-04 10:26:57 -04:00
2017-07-05 17:05:27 -04:00
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).
2016-01-22 13:41:30 -05:00
2017-07-05 17:05:27 -04:00
The `Verifier` will search for a JWT token in a http request, in the order:
2016-01-22 13:53:16 -05:00
2016-01-22 13:41:30 -05:00
1. 'jwt' URI query parameter
2. 'Authorization: BEARER T' request header
3. Cookie 'jwt' value
2017-07-05 17:05:27 -04:00
4. (optional), use `jwtauth.Verify("state")` for additional query/cookie parameter aliases
2016-01-22 13:41:30 -05:00
2017-07-05 17:05:27 -04:00
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.
2016-01-22 13:41:30 -05:00
2017-07-05 17:05:27 -04:00
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.
2016-01-22 13:41:30 -05:00
# Usage
2017-07-05 17:05:27 -04:00
See the full [example ](https://github.com/go-chi/jwtauth/blob/master/_example/main.go ).
2016-09-13 11:58:18 -04:00
2016-01-22 13:41:30 -05:00
```go
2016-09-13 11:58:18 -04:00
package main
2016-01-22 13:41:30 -05:00
import (
2016-01-22 13:45:28 -05:00
"fmt"
2016-01-22 13:42:51 -05:00
"net/http"
2017-07-05 17:05:27 -04:00
"github.com/go-chi/chi"
"github.com/go-chi/jwtauth"
2016-01-22 13:41:30 -05:00
)
var TokenAuth *jwtauth.JwtAuth
func init() {
2016-01-22 13:42:51 -05:00
TokenAuth = jwtauth.New("HS256", []byte("secret"), nil)
2017-07-05 17:05:27 -04:00
// 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())
2016-01-22 13:41:30 -05:00
}
func router() http.Handler {
2016-01-22 13:42:51 -05:00
r := chi.NewRouter()
// Protected routes
r.Group(func(r chi.Router) {
// Seek, verify and validate JWT tokens
r.Use(TokenAuth.Verifier)
// 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)
2016-08-04 10:26:57 -04:00
r.Get("/admin", func(w http.ResponseWriter, r *http.Request) {
2017-07-05 17:05:27 -04:00
_, claims, _ := jwtauth.TokenContext(r.Context())
2016-09-13 11:58:18 -04:00
w.Write([]byte(fmt.Sprintf("protected area. hi %v", claims["user_id"])))
2016-01-22 13:42:51 -05:00
})
})
// Public routes
r.Group(func(r chi.Router) {
2016-08-04 10:26:57 -04:00
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
2016-09-13 11:58:18 -04:00
w.Write([]byte("welcome anonymous"))
2016-01-22 13:42:51 -05:00
})
})
return r
2016-01-22 13:41:30 -05:00
}
```
# LICENSE
MIT