jwtmiddleware

package module
v0.0.0-...-69f2140 Latest Latest
Warning

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

Go to latest
Published: Feb 27, 2020 License: MIT Imports: 7 Imported by: 0

README

GO JWT Middleware

A middleware that will check that a JWT is sent on the Authorization header and will then set the content of the JWT into the user variable of the request.

This module lets you authenticate HTTP requests using JWT tokens in your Go Programming Language applications. JWTs are typically used to protect API endpoints, and are often issued using OpenID Connect.

Key Features

  • Ability to check the Authorization header for a JWT
  • Decode the JWT and set the content of it to the request context

Installing

go get github.com/auth0/go-jwt-middleware

Using it

You can use jwtmiddleware with default net/http as follows.

// main.go
package main

import (
  "fmt"
  "net/http"

  "github.com/auth0/go-jwt-middleware"
  "github.com/dgrijalva/jwt-go"
  "context"
)

var myHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  user := r.Context().Value("user")
  fmt.Fprintf(w, "This is an authenticated request")
  fmt.Fprintf(w, "Claim content:\n")
  for k, v := range user.(*jwt.Token).Claims.(jwt.MapClaims) {
    fmt.Fprintf(w, "%s :\t%#v\n", k, v)
  }
})

func main() {
  jwtMiddleware := jwtmiddleware.New(jwtmiddleware.Options{
    ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) {
      return []byte("My Secret"), nil
    },
    // When set, the middleware verifies that tokens are signed with the specific signing algorithm
    // If the signing method is not constant the ValidationKeyGetter callback can be used to implement additional checks
    // Important to avoid security issues described here: https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/
    SigningMethod: jwt.SigningMethodHS256,
  })

  app := jwtMiddleware.Handler(myHandler)
  http.ListenAndServe("0.0.0.0:3000", app)
}

You can also use it with Negroni as follows:

// main.go
package main

import (
  "context"
  "fmt"
  "net/http"

  "github.com/auth0/go-jwt-middleware"
  "github.com/urfave/negroni"
  "github.com/dgrijalva/jwt-go"
  "github.com/gorilla/mux"
)

var myHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  user := r.Context().Value("user");
  fmt.Fprintf(w, "This is an authenticated request")
  fmt.Fprintf(w, "Claim content:\n")
  for k, v := range user.(*jwt.Token).Claims.(jwt.MapClaims) {
    fmt.Fprintf(w, "%s :\t%#v\n", k, v)
  }
})

func main() {
  r := mux.NewRouter()

  jwtMiddleware := jwtmiddleware.New(jwtmiddleware.Options{
    ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) {
      return []byte("My Secret"), nil
    },
    // When set, the middleware verifies that tokens are signed with the specific signing algorithm
    // If the signing method is not constant the ValidationKeyGetter callback can be used to implement additional checks
    // Important to avoid security issues described here: https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/
    SigningMethod: jwt.SigningMethodHS256,
  })

  r.Handle("/ping", negroni.New(
    negroni.HandlerFunc(jwtMiddleware.HandlerWithNext),
    negroni.Wrap(myHandler),
  ))
  http.Handle("/", r)
  http.ListenAndServe(":3001", nil)
}

Options

type Options struct {
  // The function that will return the Key to validate the JWT.
  // It can be either a shared secret or a public key.
  // Default value: nil
  ValidationKeyGetter jwt.Keyfunc
  // The name of the property in the request where the user information
  // from the JWT will be stored.
  // Default value: "user"
  UserProperty string
  // The function that will be called when there's an error validating the token
  // Default value: https://github.com/auth0/go-jwt-middleware/blob/master/jwtmiddleware.go#L35
  ErrorHandler errorHandler
  // A boolean indicating if the credentials are required or not
  // Default value: false
  CredentialsOptional bool
  // A function that extracts the token from the request
  // Default: FromAuthHeader (i.e., from Authorization header as bearer token)
  Extractor TokenExtractor
  // Debug flag turns on debugging output
  // Default: false  
  Debug bool
  // When set, all requests with the OPTIONS method will use authentication
  // Default: false
  EnableAuthOnOptions bool,
  // When set, the middelware verifies that tokens are signed with the specific signing algorithm
  // If the signing method is not constant the ValidationKeyGetter callback can be used to implement additional checks
  // Important to avoid security issues described here: https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/
  // Default: nil
  SigningMethod jwt.SigningMethod
}
Token Extraction

The default value for the Extractor option is the FromAuthHeader function which assumes that the JWT will be provided as a bearer token in an Authorization header, i.e.,

Authorization: bearer {token}

To extract the token from a query string parameter, you can use the FromParameter function, e.g.,

jwtmiddleware.New(jwtmiddleware.Options{
  Extractor: jwtmiddleware.FromParameter("auth_code"),
})

In this case, the FromParameter function will look for a JWT in the auth_code query parameter.

Or, if you want to allow both, you can use the FromFirst function to try and extract the token first in one way and then in one or more other ways, e.g.,

jwtmiddleware.New(jwtmiddleware.Options{
  Extractor: jwtmiddleware.FromFirst(jwtmiddleware.FromAuthHeader,
                                     jwtmiddleware.FromParameter("auth_code")),
})
Validation of Claims

You may need to define a claim like the following:

type Claims struct {
	Email     string        `json:"email"`
	Privilege int           `json:"privilege"`
	jwt.StandardClaims
}

And you wish to restrict certain APIs for users with certain privilege value, say 0. Define a function as below:

func ValidateAdminClaim (c jwt.MapClaims) error {
	if c["privilege"] != float64(0) {
		return errors.New("Unauthorized API access")
	}
  return nil
}

The funtion type must be:

type ClaimValidatorFunc func(jwt.MapClaims) error

Call your handler as below:

...
r := mux.NewRouter()
...
_ = r.Handle("/api/users", JWTMiddleware.HandlerWithClaimValidation(getUsersHandlerFunc,
      helper.ValidateAdminClaim)).Methods("GET")

Note: Instead of passing this function in Options, I found it suitable to provide a new method HandlerWithClaimValidation so that the user may choose to provide different validation functions for different paths.

Examples

You can check out working examples in the examples folder

Author

This project is forked from https://github.com/auth0/go-jwt-middleware. Auth0

I made the changes for validation of received claims (particularly useful when you have custom claims) before dispatching the control to handler functions.

The new method added is HandlerWithClaimValidation(h http.Handler, fn ClaimValidatorFunc) http.Handler.

License

This project is licensed under the MIT license. See the LICENSE file for more info.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func FromAuthHeader

func FromAuthHeader(r *http.Request) (string, error)

FromAuthHeader is a "TokenExtractor" that takes a give request and extracts the JWT token from the Authorization header.

func OnError

func OnError(w http.ResponseWriter, r *http.Request, err string)

OnError :

Types

type ClaimValidatorFunc

type ClaimValidatorFunc func(jwt.MapClaims) error

ClaimValidatorFunc is the function type that the caller need to pass. The function should return error as nil if it finds everything is alright.

type JWTMiddleware

type JWTMiddleware struct {
	Options Options
}

JWTMiddleware is the struct with interface methods exposed

func New

func New(options ...Options) *JWTMiddleware

New constructs a new Secure instance with supplied options.

func (*JWTMiddleware) CheckJWT

func (m *JWTMiddleware) CheckJWT(w http.ResponseWriter, r *http.Request) error

CheckJWT :

func (*JWTMiddleware) Handler

func (m *JWTMiddleware) Handler(h http.Handler) http.Handler

Handler is the middleware entrypoint

func (*JWTMiddleware) HandlerWithClaimValidation

func (m *JWTMiddleware) HandlerWithClaimValidation(h http.Handler, fn ClaimValidatorFunc) http.Handler

HandlerWithClaimValidation is similar to Handler(), except that it will verify the received claim (available as a context in r) with input parameters

func (*JWTMiddleware) HandlerWithNext

func (m *JWTMiddleware) HandlerWithNext(w http.ResponseWriter, r *http.Request, next http.HandlerFunc)

HandlerWithNext is a special implementation for Negroni, but could be used elsewhere.

type Options

type Options struct {
	// The function that will return the Key to validate the JWT.
	// It can be either a shared secret or a public key.
	// Default value: nil
	ValidationKeyGetter jwt.Keyfunc
	// The name of the property in the request where the user information
	// from the JWT will be stored.
	// Default value: "user"
	UserProperty string
	// The function that will be called when there's an error validating the token
	// Default value:
	ErrorHandler errorHandler
	// A boolean indicating if the credentials are required or not
	// Default value: false
	CredentialsOptional bool
	// A function that extracts the token from the request
	// Default: FromAuthHeader (i.e., from Authorization header as bearer token)
	Extractor TokenExtractor
	// Debug flag turns on debugging output
	// Default: false
	Debug bool
	// When set, all requests with the OPTIONS method will use authentication
	// Default: false
	EnableAuthOnOptions bool
	// When set, the middelware verifies that tokens are signed with the specific signing algorithm
	// If the signing method is not constant the ValidationKeyGetter callback can be used to implement additional checks
	// Important to avoid security issues described here: https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/
	// Default: nil
	SigningMethod jwt.SigningMethod
}

Options is a struct for specifying configuration options for the middleware.

type TokenExtractor

type TokenExtractor func(r *http.Request) (string, error)

TokenExtractor is a function that takes a request as input and returns either a token or an error. An error should only be returned if an attempt to specify a token was found, but the information was somehow incorrectly formed. In the case where a token is simply not present, this should not be treated as an error. An empty string should be returned in that case.

func FromFirst

func FromFirst(extractors ...TokenExtractor) TokenExtractor

FromFirst returns a function that runs multiple token extractors and takes the first token it finds

func FromParameter

func FromParameter(param string) TokenExtractor

FromParameter returns a function that extracts the token from the specified query string parameter

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

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