package jwt import ( "time" "github.com/SermoDigital/jose/crypto" ) // JWT represents a JWT per RFC 7519. // It's described as an interface instead of a physical structure // because both JWS and JWEs can be JWTs. So, in order to use either, // import one of those two packages and use their "NewJWT" (and other) // functions. type JWT interface { // Claims returns the set of Claims. Claims() Claims // Validate returns an error describing any issues found while // validating the JWT. For info on the fn parameter, see the // comment on ValidateFunc. Validate(key interface{}, method crypto.SigningMethod, v ...*Validator) error // Serialize serializes the JWT into its on-the-wire // representation. Serialize(key interface{}) ([]byte, error) } // ValidateFunc is a function that provides access to the JWT // and allows for custom validation. Keep in mind that the Verify // methods in the JWS/JWE sibling packages call ValidateFunc *after* // validating the JWS/JWE, but *before* any validation per the JWT // RFC. Therefore, the ValidateFunc can be used to short-circuit // verification, but cannot be used to circumvent the RFC. // Custom JWT implementations are free to abuse this, but it is // not recommended. type ValidateFunc func(Claims) error // Validator represents some of the validation options. type Validator struct { Expected Claims // If non-nil, these are required to match. EXP time.Duration // EXPLeeway NBF time.Duration // NBFLeeway Fn ValidateFunc // See ValidateFunc for more information. _ struct{} // Require explicitly-named struct fields. } // Validate validates the JWT based on the expected claims in v. // Note: it only validates the registered claims per // https://tools.ietf.org/html/rfc7519#section-4.1 // // Custom claims should be validated using v's Fn member. func (v *Validator) Validate(j JWT) error { if iss, ok := v.Expected.Issuer(); ok && j.Claims().Get("iss") != iss { return ErrInvalidISSClaim } if sub, ok := v.Expected.Subject(); ok && j.Claims().Get("sub") != sub { return ErrInvalidSUBClaim } if iat, ok := v.Expected.IssuedAt(); ok { if t, ok := j.Claims().GetTime("iat"); !t.Equal(iat) || !ok { return ErrInvalidIATClaim } } if jti, ok := v.Expected.JWTID(); ok && j.Claims().Get("jti") != jti { return ErrInvalidJTIClaim } if aud, ok := v.Expected.Audience(); ok { aud2, ok := j.Claims().Audience() if !ok || !ValidAudience(aud, aud2) { return ErrInvalidAUDClaim } } if v.Fn != nil { return v.Fn(j.Claims()) } return nil } // SetClaim sets the claim with the given val. func (v *Validator) SetClaim(claim string, val interface{}) { v.expect() v.Expected.Set(claim, val) } // SetIssuer sets the "iss" claim per // https://tools.ietf.org/html/rfc7519#section-4.1.1 func (v *Validator) SetIssuer(iss string) { v.expect() v.Expected.Set("iss", iss) } // SetSubject sets the "sub" claim per // https://tools.ietf.org/html/rfc7519#section-4.1.2 func (v *Validator) SetSubject(sub string) { v.expect() v.Expected.Set("sub", sub) } // SetAudience sets the "aud" claim per // https://tools.ietf.org/html/rfc7519#section-4.1.3 func (v *Validator) SetAudience(aud string) { v.expect() v.Expected.Set("aud", aud) } // SetExpiration sets the "exp" claim per // https://tools.ietf.org/html/rfc7519#section-4.1.4 func (v *Validator) SetExpiration(exp time.Time) { v.expect() v.Expected.Set("exp", exp) } // SetNotBefore sets the "nbf" claim per // https://tools.ietf.org/html/rfc7519#section-4.1.5 func (v *Validator) SetNotBefore(nbf time.Time) { v.expect() v.Expected.Set("nbf", nbf) } // SetIssuedAt sets the "iat" claim per // https://tools.ietf.org/html/rfc7519#section-4.1.6 func (v *Validator) SetIssuedAt(iat time.Time) { v.expect() v.Expected.Set("iat", iat) } // SetJWTID sets the "jti" claim per // https://tools.ietf.org/html/rfc7519#section-4.1.7 func (v *Validator) SetJWTID(jti string) { v.expect() v.Expected.Set("jti", jti) } func (v *Validator) expect() { if v.Expected == nil { v.Expected = make(Claims) } }