diff --git a/auth0.go b/auth0.go index c664fc9..91931f2 100644 --- a/auth0.go +++ b/auth0.go @@ -34,31 +34,57 @@ func NewKeyProvider(key interface{}) SecretProvider { var ( // ErrNoJWTHeaders is returned when there are no headers in the JWT. ErrNoJWTHeaders = errors.New("No headers in the token") + // ErrJWTFromTokenNotImplemented is returned when the secret provider cannot + // obtain a . + ErrJWTFromTokenNotImplemented = errors.New("Cannot extract JWT from Token: not implemented") ) +// TokenSecertProvider allows to extract the key ID from a JSONWebToken +// directly, and get the secret from it +type TokenSecretProvider interface { + SecretFromToken(token *jwt.JSONWebToken) (interface{}, error) +} + +type nopTokenSecretProvider struct{} + +func (p *nopTokenSecretProvider) SecretFromToken(token *jwt.JSONWebToken) (interface{}, error) { + return nil, ErrJWTFromTokenNotImplemented +} + // Configuration contains // all the information about the // Auth0 service. type Configuration struct { - secretProvider SecretProvider - expectedClaims jwt.Expected - signIn jose.SignatureAlgorithm + secretProvider SecretProvider + expectedClaims jwt.Expected + signIn jose.SignatureAlgorithm + tokenSecretProvider TokenSecretProvider } // NewConfiguration creates a configuration for server func NewConfiguration(provider SecretProvider, audience []string, issuer string, method jose.SignatureAlgorithm) Configuration { + tokenSecretProvider, ok := provider.(TokenSecretProvider) + if !ok { + tokenSecretProvider = &nopTokenSecretProvider{} + } return Configuration{ - secretProvider: provider, - expectedClaims: jwt.Expected{Issuer: issuer, Audience: audience}, - signIn: method, + secretProvider: provider, + expectedClaims: jwt.Expected{Issuer: issuer, Audience: audience}, + signIn: method, + tokenSecretProvider: tokenSecretProvider, } } // NewConfigurationTrustProvider creates a configuration for server with no enforcement for token sig alg type, instead trust provider func NewConfigurationTrustProvider(provider SecretProvider, audience []string, issuer string) Configuration { + tokenSecretProvider, ok := provider.(TokenSecretProvider) + if !ok { + tokenSecretProvider = &nopTokenSecretProvider{} + } return Configuration{ - secretProvider: provider, - expectedClaims: jwt.Expected{Issuer: issuer, Audience: audience}, + secretProvider: provider, + expectedClaims: jwt.Expected{Issuer: issuer, Audience: audience}, + tokenSecretProvider: tokenSecretProvider, } } @@ -92,14 +118,8 @@ func NewValidatorWithLeeway(config Configuration, extractor RequestTokenExtracto } } -// ValidateRequest validates the token within -// the http request. -func (v *JWTValidator) ValidateRequest(r *http.Request) (*jwt.JSONWebToken, error) { - token, err := v.extractor.Extract(r) - if err != nil { - return nil, err - } - +// Validate validates a jwt.JSONWebToken +func (v *JWTValidator) Validate(token *jwt.JSONWebToken, secretKey interface{}) (*jwt.JSONWebToken, error) { if len(token.Headers) < 1 { return nil, ErrNoJWTHeaders } @@ -113,18 +133,48 @@ func (v *JWTValidator) ValidateRequest(r *http.Request) (*jwt.JSONWebToken, erro } claims := jwt.Claims{} - key, err := v.config.secretProvider.GetSecret(r) + if err := token.Claims(secretKey, &claims); err != nil { + return nil, err + } + + expected := v.config.expectedClaims.WithTime(time.Now()) + err := claims.ValidateWithLeeway(expected, v.leeway) + return token, err +} + +// ValidateSigned validates a non parsed token in string form +func (v *JWTValidator) ValidateToken(token *jwt.JSONWebToken) (*jwt.JSONWebToken, error) { + secretKey, err := v.config.tokenSecretProvider.SecretFromToken(token) if err != nil { return nil, err } + return v.Validate(token, secretKey) +} - if err = token.Claims(key, &claims); err != nil { +// ValidateSigned validates a non parsed token in string form +func (v *JWTValidator) ValidateSigned(s string) (*jwt.JSONWebToken, error) { + if s == "" { + return nil, ErrTokenNotFound + } + token, err := jwt.ParseSigned(s) + if err != nil { return nil, err } + return v.ValidateToken(token) +} - expected := v.config.expectedClaims.WithTime(time.Now()) - err = claims.ValidateWithLeeway(expected, v.leeway) - return token, err +// ValidateRequest validates the token within +// the http request. +func (v *JWTValidator) ValidateRequest(r *http.Request) (*jwt.JSONWebToken, error) { + token, err := v.extractor.Extract(r) + if err != nil { + return nil, err + } + key, err := v.config.secretProvider.GetSecret(r) + if err != nil { + return nil, err + } + return v.Validate(token, key) } // Claims unmarshall the claims of the provided token @@ -135,3 +185,12 @@ func (v *JWTValidator) Claims(r *http.Request, token *jwt.JSONWebToken, values . } return token.Claims(key, values...) } + +// ClaimsFromToken unmarshall the claims of the provided token +func (v *JWTValidator) ClaimsFromToken(token *jwt.JSONWebToken, values ...interface{}) error { + key, err := v.config.tokenSecretProvider.SecretFromToken(token) + if err != nil { + return err + } + return token.Claims(key, values...) +}