New returns a middleware to be used with the JWTSecurity DSL definitions of goa. It supports the scopes claim in the JWT and ensures goa-defined Security DSLs are properly validated.

The steps taken by the middleware are:

1. Validate the "Bearer" token present in the "Authorization" header against the key(s)
   given to New
2. If scopes are defined in the design for the action validate them against the "scopes" JWT

The `exp` (expiration) and `nbf` (not before) date checks are validated by the JWT library.

validationKeys can be one of these:

* a single string
* a single []byte
* a list of string
* a list of []byte
* a single rsa.PublicKey
* a list of rsa.PublicKey

The type of the keys determine the algorithms that will be used to do the check. The goal of having lists of keys is to allow for key rotation, still check the previous keys until rotation has been completed.

You can define an optional function to do additional validations on the token once the signature and the claims requirements are proven to be valid. Example:

validationHandler, _ := goa.NewMiddleware(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
    token := jwt.ContextJWT(ctx)
    if val, ok := token.Claims["is_uncle"].(string); !ok || val != "ben" {
        return jwt.ErrJWTError("you are not uncle ben's")

Mount the middleware with the generated UseXX function where XX is the name of the scheme as defined in the design, e.g.:

app.UseJWT(jwt.New("secret", validationHandler, app.NewJWTSecurity()))

New is referenced in 6 repositories



func New(resolver KeyResolver, validationFunc goa.Middleware, scheme *goa.JWTSecurity) goa.Middleware {
	return func(nextHandler goa.Handler) goa.Handler {
		return func(ctx context.Context, rw http.ResponseWriter, req *http.Request) error {
			// TODO: implement the QUERY string handler too
			if scheme.In != goa.LocHeader {
				return fmt.Errorf("whoops, security scheme with location (in) %q not supported", scheme.In)
			val := req.Header.Get(scheme.Name)
			if val == "" {
				return ErrJWTError(fmt.Sprintf("missing header %q", scheme.Name))

			if !strings.HasPrefix(strings.ToLower(val), "bearer ") {
				return ErrJWTError(fmt.Sprintf("invalid or malformed %q header, expected 'Authorization: Bearer JWT-token...'", val))

			incomingToken := strings.Split(val, " ")[1]

			var (
				rsaKeys  []*rsa.PublicKey
				hmacKeys [][]byte
				keys     = resolver.SelectKeys(req)
				for _, key := range keys {
					switch k := key.(type) {
					case *rsa.PublicKey:
						rsaKeys = append(rsaKeys, k)
					case []byte:
						hmacKeys = append(hmacKeys, k)
					case string:
						hmacKeys = append(hmacKeys, []byte(k))
			var (
				token     *jwt.Token
				err       error
				validated = false

			if len(rsaKeys) > 0 {
				token, err = validateRSAKeys(rsaKeys, "RS", incomingToken)
				if err == nil {
					validated = true

			if !validated && len(hmacKeys) > 0 {
				token, err = validateHMACKeys(hmacKeys, "HS", incomingToken)
				if err == nil {
					validated = true

			if !validated {
				return ErrJWTError("JWT validation failed")

			scopesInClaim, scopesInClaimList, err := parseClaimScopes(token)
			if err != nil {
				goa.LogError(ctx, err.Error())
				return ErrJWTError(err)

			requiredScopes := goa.ContextRequiredScopes(ctx)

			for _, scope := range requiredScopes {
				if !scopesInClaim[scope] {
					msg := "authorization failed: required 'scopes' not present in JWT claim"
					return ErrJWTError(msg, "required", requiredScopes, "scopes", scopesInClaimList)

			ctx = WithJWT(ctx, token)
			if validationFunc != nil {