This package has as purpose will help you to check the validness of any token based on JWT spec.
$ go get github.com/mfuentesg/go-jwtmiddleware
You can use it with the net/http
package or even with a middleware-focused library like Negroni.
package main
import (
"fmt"
"log"
"net/http"
"github.com/mfuentesg/go-jwtmiddleware"
)
func helloWorld(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("hello world!"))
}
func main() {
m := jwtmiddleware.New(jwtmiddleware.WithSignKey([]byte("secret")))
http.Handle("/", m.Handler(http.HandlerFunc(helloWorld)))
fmt.Println("listening on port :3000")
log.Fatal(http.ListenAndServe(":3000", nil))
}
package main
import (
"net/http"
"github.com/codegangsta/negroni"
"github.com/mfuentesg/go-jwtmiddleware"
)
func main() {
m := jwtmiddleware.New(jwtmiddleware.WithSignKey("user"))
n := negroni.Classic()
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("hello world!"))
})
n.UseFunc(m.HandlerNext)
n.UseHandler(mux)
http.ListenAndServe(":3000", n)
}
This project is based on functional options
concept, to set the initial settings of the middleware. These options must be passed on the jwtmiddleware.New()
function which options are of the type MiddlewareOption func(*options)
.
This property is a callback
to control the ocurred errors on the validation process.
Unlike other middlewares, this package returns jwt-go native errors, given you the posibility to check errors with the defined contants, for example jwt.ErrSignatureInvalid
.
package main
import (
"fmt"
"log"
"net/http"
mdw "github.com/mfuentesg/go-jwtmiddleware"
)
func errorHandler(w http.ResponseWriter, r *http.Request, err error) {
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte(fmt.Sprintf("unauthorized : %v", err)))
}
func main() {
m := mdw.New(mdw.WithSignKey([]byte("secret")), mdw.WithErrorHandler(errorHandler))
http.Handle("/", m.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("hello world!"))
})))
fmt.Println("listening on port :3000")
log.Fatal(http.ListenAndServe(":3000", nil))
}
This property allows you to get token value from any place, by default the token will be extracted from the Authorization
header on the incominng request.
package main
import (
"fmt"
"log"
"net/http"
"github.com/golang-jwt/jwt/v4"
mdw "github.com/mfuentesg/go-jwtmiddleware"
)
func errorHandler(w http.ResponseWriter, r *http.Request, err error) {
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte(fmt.Sprintf("unauthorized : %v", err)))
}
func main() {
m := mdw.New()
http.Handle("/", m.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := r.Context().Value("user").(*jwt.Token).Claims.(jwt.MapClaims)
w.WriteHeader(http.StatusOK)
w.Write([]byte(fmt.Sprintf("hello world %s!", token["name"])))
})))
fmt.Println("listening on port :3000")
log.Fatal(http.ListenAndServe(":3000", nil))
}
$ curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.XbPfbIHMI6arZ3Y922BhjWgQzWXcXNrz0ogtVhfEd2o" localhost:3000
hello world John Doe!
This property indicates the used algorithm to encrypt the token, i.e. jwt.SigningMethodES256
.
package main
import (
"fmt"
"log"
"net/http"
"github.com/golang-jwt/jwt/v4"
mdw "github.com/mfuentesg/go-jwtmiddleware"
)
func main() {
m := mdw.New(mdw.WithSigningMethod())
http.Handle("/", m.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := r.Context().Value("user").(*jwt.Token).Claims.(jwt.MapClaims)
w.WriteHeader(http.StatusOK)
w.Write([]byte(fmt.Sprintf("hello world %s!", token["name"])))
})))
fmt.Println("listening on port :3000")
log.Fatal(http.ListenAndServe(":3000", nil))
}
It used to set the secret key to encrypt/decrypt the token.
package main
import (
"fmt"
"log"
"net/http"
"github.com/golang-jwt/jwt/v4"
mdw "github.com/mfuentesg/go-jwtmiddleware"
)
func main() {
m := mdw.New(mdw.WithSignKey([]byte("my secret key")))
http.Handle("/", m.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := r.Context().Value("user").(*jwt.Token).Claims.(jwt.MapClaims)
w.WriteHeader(http.StatusOK)
w.Write([]byte(fmt.Sprintf("hello world %s!", token["name"])))
})))
fmt.Println("listening on port :3000")
log.Fatal(http.ListenAndServe(":3000", nil))
}
# token created with the secret `secret`
$ curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.XbPfbIHMI6arZ3Y922BhjWgQzWXcXNrz0ogtVhfEd2o" localhost:3000
unauthorized
It defines the name of the property in the request where the token will be stored.
package main
import (
"fmt"
"log"
"net/http"
"github.com/golang-jwt/jwt/v4"
mdw "github.com/mfuentesg/go-jwtmiddleware"
)
type userKey string
func errorHandler(w http.ResponseWriter, r *http.Request, err error) {
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte(fmt.Sprintf("unauthorized : %v", err)))
}
func main() {
m := mdw.New(mdw.WithSignKey([]byte("secret")), mdw.WithUserProperty(userKey("user")))
http.Handle("/", m.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := r.Context().Value(userKey("user")).(*jwt.Token).Claims.(jwt.MapClaims)
w.WriteHeader(http.StatusOK)
w.Write([]byte(fmt.Sprintf("hello world %s!", token["name"])))
})))
fmt.Println("listening on port :3000")
log.Fatal(http.ListenAndServe(":3000", nil))
}
$ curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.XbPfbIHMI6arZ3Y922BhjWgQzWXcXNrz0ogtVhfEd2o" localhost:3000
hello world John Doe!