mirror of https://github.com/golang-jwt/jwt.git
More documentation cleanup
This commit is contained in:
parent
57662e57d3
commit
4e6e1ba2bb
|
@ -4,8 +4,8 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MapClaims is a claims type that uses the map[string]interface{} for JSON decoding.
|
// MapClaims is a claims type that uses the map[string]interface{} for JSON
|
||||||
// This is the default claims type if you don't supply one
|
// decoding. This is the default claims type if you don't supply one
|
||||||
type MapClaims map[string]interface{}
|
type MapClaims map[string]interface{}
|
||||||
|
|
||||||
// GetExpirationTime implements the Claims interface.
|
// GetExpirationTime implements the Claims interface.
|
||||||
|
|
|
@ -2,28 +2,32 @@ package jwt
|
||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
// ParserOption is used to implement functional-style options that modify the behavior of the parser. To add
|
// ParserOption is used to implement functional-style options that modify the
|
||||||
// new options, just create a function (ideally beginning with With or Without) that returns an anonymous function that
|
// behavior of the parser. To add new options, just create a function (ideally
|
||||||
// takes a *Parser type as input and manipulates its configuration accordingly.
|
// beginning with With or Without) that returns an anonymous function that takes
|
||||||
|
// a *Parser type as input and manipulates its configuration accordingly.
|
||||||
type ParserOption func(*Parser)
|
type ParserOption func(*Parser)
|
||||||
|
|
||||||
// WithValidMethods is an option to supply algorithm methods that the parser will check. Only those methods will be considered valid.
|
// WithValidMethods is an option to supply algorithm methods that the parser
|
||||||
// It is heavily encouraged to use this option in order to prevent attacks such as https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/.
|
// will check. Only those methods will be considered valid. It is heavily
|
||||||
|
// encouraged to use this option in order to prevent attacks such as
|
||||||
|
// https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/.
|
||||||
func WithValidMethods(methods []string) ParserOption {
|
func WithValidMethods(methods []string) ParserOption {
|
||||||
return func(p *Parser) {
|
return func(p *Parser) {
|
||||||
p.validMethods = methods
|
p.validMethods = methods
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithJSONNumber is an option to configure the underlying JSON parser with UseNumber
|
// WithJSONNumber is an option to configure the underlying JSON parser with
|
||||||
|
// UseNumber.
|
||||||
func WithJSONNumber() ParserOption {
|
func WithJSONNumber() ParserOption {
|
||||||
return func(p *Parser) {
|
return func(p *Parser) {
|
||||||
p.useJSONNumber = true
|
p.useJSONNumber = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithoutClaimsValidation is an option to disable claims validation. This option should only be used if you exactly know
|
// WithoutClaimsValidation is an option to disable claims validation. This
|
||||||
// what you are doing.
|
// option should only be used if you exactly know what you are doing.
|
||||||
func WithoutClaimsValidation() ParserOption {
|
func WithoutClaimsValidation() ParserOption {
|
||||||
return func(p *Parser) {
|
return func(p *Parser) {
|
||||||
p.skipClaimsValidation = true
|
p.skipClaimsValidation = true
|
||||||
|
@ -58,9 +62,10 @@ func WithIssuedAt() ParserOption {
|
||||||
// the `aud` claim. Validation will fail if the audience is not listed in the
|
// the `aud` claim. Validation will fail if the audience is not listed in the
|
||||||
// token or the `aud` claim is missing.
|
// token or the `aud` claim is missing.
|
||||||
//
|
//
|
||||||
// NOTE: While the `aud` claim is OPTIONAL is a JWT, the handling of it is
|
// NOTE: While the `aud` claim is OPTIONAL in a JWT, the handling of it is
|
||||||
// application-specific. Since this validation API is helping developers in
|
// application-specific. Since this validation API is helping developers in
|
||||||
// writing secure application, we decided to REQUIRE the existence of the claim.
|
// writing secure application, we decided to REQUIRE the existence of the claim,
|
||||||
|
// if an audience is expected.
|
||||||
func WithAudience(aud string) ParserOption {
|
func WithAudience(aud string) ParserOption {
|
||||||
return func(p *Parser) {
|
return func(p *Parser) {
|
||||||
p.validator.expectedAud = aud
|
p.validator.expectedAud = aud
|
||||||
|
@ -71,9 +76,10 @@ func WithAudience(aud string) ParserOption {
|
||||||
// `iss` claim. Validation will fail if a different issuer is specified in the
|
// `iss` claim. Validation will fail if a different issuer is specified in the
|
||||||
// token or the `iss` claim is missing.
|
// token or the `iss` claim is missing.
|
||||||
//
|
//
|
||||||
// NOTE: While the `iss` claim is OPTIONAL is a JWT, the handling of it is
|
// NOTE: While the `iss` claim is OPTIONAL in a JWT, the handling of it is
|
||||||
// application-specific. Since this validation API is helping developers in
|
// application-specific. Since this validation API is helping developers in
|
||||||
// writing secure application, we decided to REQUIRE the existence of the claim.
|
// writing secure application, we decided to REQUIRE the existence of the claim,
|
||||||
|
// if an issuer is expected.
|
||||||
func WithIssuer(iss string) ParserOption {
|
func WithIssuer(iss string) ParserOption {
|
||||||
return func(p *Parser) {
|
return func(p *Parser) {
|
||||||
p.validator.expectedIss = iss
|
p.validator.expectedIss = iss
|
||||||
|
@ -84,9 +90,10 @@ func WithIssuer(iss string) ParserOption {
|
||||||
// `sub` claim. Validation will fail if a different subject is specified in the
|
// `sub` claim. Validation will fail if a different subject is specified in the
|
||||||
// token or the `sub` claim is missing.
|
// token or the `sub` claim is missing.
|
||||||
//
|
//
|
||||||
// NOTE: While the `sub` claim is OPTIONAL is a JWT, the handling of it is
|
// NOTE: While the `sub` claim is OPTIONAL in a JWT, the handling of it is
|
||||||
// application-specific. Since this validation API is helping developers in
|
// application-specific. Since this validation API is helping developers in
|
||||||
// writing secure application, we decided to REQUIRE the existence of the claim.
|
// writing secure application, we decided to REQUIRE the existence of the claim,
|
||||||
|
// if a subject is expected.
|
||||||
func WithSubject(sub string) ParserOption {
|
func WithSubject(sub string) ParserOption {
|
||||||
return func(p *Parser) {
|
return func(p *Parser) {
|
||||||
p.validator.expectedSub = sub
|
p.validator.expectedSub = sub
|
||||||
|
|
86
token.go
86
token.go
|
@ -6,42 +6,49 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DecodePaddingAllowed will switch the codec used for decoding JWTs respectively. Note that the JWS RFC7515
|
// DecodePaddingAllowed will switch the codec used for decoding JWTs
|
||||||
// states that the tokens will utilize a Base64url encoding with no padding. Unfortunately, some implementations
|
// respectively. Note that the JWS RFC7515 states that the tokens will utilize a
|
||||||
// of JWT are producing non-standard tokens, and thus require support for decoding. Note that this is a global
|
// Base64url encoding with no padding. Unfortunately, some implementations of
|
||||||
// variable, and updating it will change the behavior on a package level, and is also NOT go-routine safe.
|
// JWT are producing non-standard tokens, and thus require support for decoding.
|
||||||
// To use the non-recommended decoding, set this boolean to `true` prior to using this package.
|
// Note that this is a global variable, and updating it will change the behavior
|
||||||
|
// on a package level, and is also NOT go-routine safe. To use the
|
||||||
|
// non-recommended decoding, set this boolean to `true` prior to using this
|
||||||
|
// package.
|
||||||
var DecodePaddingAllowed bool
|
var DecodePaddingAllowed bool
|
||||||
|
|
||||||
// DecodeStrict will switch the codec used for decoding JWTs into strict mode.
|
// DecodeStrict will switch the codec used for decoding JWTs into strict mode.
|
||||||
// In this mode, the decoder requires that trailing padding bits are zero, as described in RFC 4648 section 3.5.
|
// In this mode, the decoder requires that trailing padding bits are zero, as
|
||||||
// Note that this is a global variable, and updating it will change the behavior on a package level, and is also NOT go-routine safe.
|
// described in RFC 4648 section 3.5. Note that this is a global variable, and
|
||||||
// To use strict decoding, set this boolean to `true` prior to using this package.
|
// updating it will change the behavior on a package level, and is also NOT
|
||||||
|
// go-routine safe. To use strict decoding, set this boolean to `true` prior to
|
||||||
|
// using this package.
|
||||||
var DecodeStrict bool
|
var DecodeStrict bool
|
||||||
|
|
||||||
// Keyfunc will be used by the Parse methods as a callback function to supply
|
// Keyfunc will be used by the Parse methods as a callback function to supply
|
||||||
// the key for verification. The function receives the parsed,
|
// the key for verification. The function receives the parsed, but unverified
|
||||||
// but unverified Token. This allows you to use properties in the
|
// Token. This allows you to use properties in the Header of the token (such as
|
||||||
// Header of the token (such as `kid`) to identify which key to use.
|
// `kid`) to identify which key to use.
|
||||||
type Keyfunc func(*Token) (interface{}, error)
|
type Keyfunc func(*Token) (interface{}, error)
|
||||||
|
|
||||||
// Token represents a JWT Token. Different fields will be used depending on whether you're
|
// Token represents a JWT Token. Different fields will be used depending on
|
||||||
// creating or parsing/verifying a token.
|
// whether you're creating or parsing/verifying a token.
|
||||||
type Token struct {
|
type Token struct {
|
||||||
Raw string // The raw token. Populated when you Parse a token
|
Raw string // Raw contains the raw token. Populated when you [Parse] a token
|
||||||
Method SigningMethod // The signing method used or to be used
|
Method SigningMethod // Method is the signing method used or to be used
|
||||||
Header map[string]interface{} // The first segment of the token
|
Header map[string]interface{} // Header is the first segment of the token
|
||||||
Claims Claims // The second segment of the token
|
Claims Claims // Claims is the second segment of the token
|
||||||
Signature string // The third segment of the token. Populated when you Parse a token
|
Signature string // Signature is the third segment of the token. Populated when you Parse a token
|
||||||
Valid bool // Is the token valid? Populated when you Parse/Verify a token
|
Valid bool // Valid specifies if the token is valid. Populated when you Parse/Verify a token
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new Token with the specified signing method and an empty map of claims.
|
// New creates a new [Token] with the specified signing method and an empty map of
|
||||||
|
// claims.
|
||||||
func New(method SigningMethod) *Token {
|
func New(method SigningMethod) *Token {
|
||||||
return NewWithClaims(method, MapClaims{})
|
return NewWithClaims(method, MapClaims{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWithClaims creates a new Token with the specified signing method and claims.
|
// NewWithClaims creates a new [Token] with the specified signing method and
|
||||||
|
// claims.
|
||||||
func NewWithClaims(method SigningMethod, claims Claims) *Token {
|
func NewWithClaims(method SigningMethod, claims Claims) *Token {
|
||||||
return &Token{
|
return &Token{
|
||||||
Header: map[string]interface{}{
|
Header: map[string]interface{}{
|
||||||
|
@ -53,8 +60,8 @@ func NewWithClaims(method SigningMethod, claims Claims) *Token {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignedString creates and returns a complete, signed JWT.
|
// SignedString creates and returns a complete, signed JWT. The token is signed
|
||||||
// The token is signed using the SigningMethod specified in the token.
|
// using the SigningMethod specified in the token.
|
||||||
func (t *Token) SignedString(key interface{}) (string, error) {
|
func (t *Token) SignedString(key interface{}) (string, error) {
|
||||||
var sig, sstr string
|
var sig, sstr string
|
||||||
var err error
|
var err error
|
||||||
|
@ -67,10 +74,9 @@ func (t *Token) SignedString(key interface{}) (string, error) {
|
||||||
return strings.Join([]string{sstr, sig}, "."), nil
|
return strings.Join([]string{sstr, sig}, "."), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SigningString generates the signing string. This is the
|
// SigningString generates the signing string. This is the most expensive part
|
||||||
// most expensive part of the whole deal. Unless you
|
// of the whole deal. Unless you need this for something special, just go
|
||||||
// need this for something special, just go straight for
|
// straight for the SignedString.
|
||||||
// the SignedString.
|
|
||||||
func (t *Token) SigningString() (string, error) {
|
func (t *Token) SigningString() (string, error) {
|
||||||
var err error
|
var err error
|
||||||
var jsonValue []byte
|
var jsonValue []byte
|
||||||
|
@ -90,36 +96,38 @@ func (t *Token) SigningString() (string, error) {
|
||||||
|
|
||||||
// Parse parses, validates, verifies the signature and returns the parsed token.
|
// Parse parses, validates, verifies the signature and returns the parsed token.
|
||||||
// keyFunc will receive the parsed token and should return the cryptographic key
|
// keyFunc will receive the parsed token and should return the cryptographic key
|
||||||
// for verifying the signature.
|
// for verifying the signature. The caller is strongly encouraged to set the
|
||||||
// The caller is strongly encouraged to set the WithValidMethods option to
|
// WithValidMethods option to validate the 'alg' claim in the token matches the
|
||||||
// validate the 'alg' claim in the token matches the expected algorithm.
|
// expected algorithm. For more details about the importance of validating the
|
||||||
// For more details about the importance of validating the 'alg' claim,
|
// 'alg' claim, see
|
||||||
// see https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/
|
// https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/
|
||||||
func Parse(tokenString string, keyFunc Keyfunc, options ...ParserOption) (*Token, error) {
|
func Parse(tokenString string, keyFunc Keyfunc, options ...ParserOption) (*Token, error) {
|
||||||
return NewParser(options...).Parse(tokenString, keyFunc)
|
return NewParser(options...).Parse(tokenString, keyFunc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseWithClaims is a shortcut for NewParser().ParseWithClaims().
|
// ParseWithClaims is a shortcut for NewParser().ParseWithClaims().
|
||||||
//
|
//
|
||||||
// Note: If you provide a custom claim implementation that embeds one of the standard claims (such as RegisteredClaims),
|
// Note: If you provide a custom claim implementation that embeds one of the
|
||||||
// make sure that a) you either embed a non-pointer version of the claims or b) if you are using a pointer, allocate the
|
// standard claims (such as RegisteredClaims), make sure that a) you either
|
||||||
// proper memory for it before passing in the overall claims, otherwise you might run into a panic.
|
// embed a non-pointer version of the claims or b) if you are using a pointer,
|
||||||
|
// allocate the proper memory for it before passing in the overall claims,
|
||||||
|
// otherwise you might run into a panic.
|
||||||
func ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc, options ...ParserOption) (*Token, error) {
|
func ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc, options ...ParserOption) (*Token, error) {
|
||||||
return NewParser(options...).ParseWithClaims(tokenString, claims, keyFunc)
|
return NewParser(options...).ParseWithClaims(tokenString, claims, keyFunc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncodeSegment encodes a JWT specific base64url encoding with padding stripped
|
// EncodeSegment encodes a JWT specific base64url encoding with padding stripped
|
||||||
//
|
//
|
||||||
// Deprecated: In a future release, we will demote this function to a non-exported function, since it
|
// Deprecated: In a future release, we will demote this function to a
|
||||||
// should only be used internally
|
// non-exported function, since it should only be used internally
|
||||||
func EncodeSegment(seg []byte) string {
|
func EncodeSegment(seg []byte) string {
|
||||||
return base64.RawURLEncoding.EncodeToString(seg)
|
return base64.RawURLEncoding.EncodeToString(seg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeSegment decodes a JWT specific base64url encoding with padding stripped
|
// DecodeSegment decodes a JWT specific base64url encoding with padding stripped
|
||||||
//
|
//
|
||||||
// Deprecated: In a future release, we will demote this function to a non-exported function, since it
|
// Deprecated: In a future release, we will demote this function to a
|
||||||
// should only be used internally
|
// non-exported function, since it should only be used internally
|
||||||
func DecodeSegment(seg string) ([]byte, error) {
|
func DecodeSegment(seg string) ([]byte, error) {
|
||||||
encoding := base64.RawURLEncoding
|
encoding := base64.RawURLEncoding
|
||||||
|
|
||||||
|
|
43
types.go
43
types.go
|
@ -9,22 +9,23 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TimePrecision sets the precision of times and dates within this library.
|
// TimePrecision sets the precision of times and dates within this library. This
|
||||||
// This has an influence on the precision of times when comparing expiry or
|
// has an influence on the precision of times when comparing expiry or other
|
||||||
// other related time fields. Furthermore, it is also the precision of times
|
// related time fields. Furthermore, it is also the precision of times when
|
||||||
// when serializing.
|
// serializing.
|
||||||
//
|
//
|
||||||
// For backwards compatibility the default precision is set to seconds, so that
|
// For backwards compatibility the default precision is set to seconds, so that
|
||||||
// no fractional timestamps are generated.
|
// no fractional timestamps are generated.
|
||||||
var TimePrecision = time.Second
|
var TimePrecision = time.Second
|
||||||
|
|
||||||
// MarshalSingleStringAsArray modifies the behaviour of the ClaimStrings type, especially
|
// MarshalSingleStringAsArray modifies the behavior of the ClaimStrings type,
|
||||||
// its MarshalJSON function.
|
// especially its MarshalJSON function.
|
||||||
//
|
//
|
||||||
// If it is set to true (the default), it will always serialize the type as an
|
// If it is set to true (the default), it will always serialize the type as an
|
||||||
// array of strings, even if it just contains one element, defaulting to the behaviour
|
// array of strings, even if it just contains one element, defaulting to the
|
||||||
// of the underlying []string. If it is set to false, it will serialize to a single
|
// behavior of the underlying []string. If it is set to false, it will serialize
|
||||||
// string, if it contains one element. Otherwise, it will serialize to an array of strings.
|
// to a single string, if it contains one element. Otherwise, it will serialize
|
||||||
|
// to an array of strings.
|
||||||
var MarshalSingleStringAsArray = true
|
var MarshalSingleStringAsArray = true
|
||||||
|
|
||||||
// NumericDate represents a JSON numeric date value, as referenced at
|
// NumericDate represents a JSON numeric date value, as referenced at
|
||||||
|
@ -58,9 +59,10 @@ func (date NumericDate) MarshalJSON() (b []byte, err error) {
|
||||||
// For very large timestamps, UnixNano would overflow an int64, but this
|
// For very large timestamps, UnixNano would overflow an int64, but this
|
||||||
// function requires nanosecond level precision, so we have to use the
|
// function requires nanosecond level precision, so we have to use the
|
||||||
// following technique to get round the issue:
|
// following technique to get round the issue:
|
||||||
|
//
|
||||||
// 1. Take the normal unix timestamp to form the whole number part of the
|
// 1. Take the normal unix timestamp to form the whole number part of the
|
||||||
// output,
|
// output,
|
||||||
// 2. Take the result of the Nanosecond function, which retuns the offset
|
// 2. Take the result of the Nanosecond function, which returns the offset
|
||||||
// within the second of the particular unix time instance, to form the
|
// within the second of the particular unix time instance, to form the
|
||||||
// decimal part of the output
|
// decimal part of the output
|
||||||
// 3. Concatenate them to produce the final result
|
// 3. Concatenate them to produce the final result
|
||||||
|
@ -72,9 +74,10 @@ func (date NumericDate) MarshalJSON() (b []byte, err error) {
|
||||||
return output, nil
|
return output, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON is an implementation of the json.RawMessage interface and deserializses a
|
// UnmarshalJSON is an implementation of the json.RawMessage interface and
|
||||||
// NumericDate from a JSON representation, i.e. a json.Number. This number represents an UNIX epoch
|
// deserializes a [NumericDate] from a JSON representation, i.e. a
|
||||||
// with either integer or non-integer seconds.
|
// [json.Number]. This number represents an UNIX epoch with either integer or
|
||||||
|
// non-integer seconds.
|
||||||
func (date *NumericDate) UnmarshalJSON(b []byte) (err error) {
|
func (date *NumericDate) UnmarshalJSON(b []byte) (err error) {
|
||||||
var (
|
var (
|
||||||
number json.Number
|
number json.Number
|
||||||
|
@ -95,8 +98,9 @@ func (date *NumericDate) UnmarshalJSON(b []byte) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClaimStrings is basically just a slice of strings, but it can be either serialized from a string array or just a string.
|
// ClaimStrings is basically just a slice of strings, but it can be either
|
||||||
// This type is necessary, since the "aud" claim can either be a single string or an array.
|
// serialized from a string array or just a string. This type is necessary,
|
||||||
|
// since the "aud" claim can either be a single string or an array.
|
||||||
type ClaimStrings []string
|
type ClaimStrings []string
|
||||||
|
|
||||||
func (s *ClaimStrings) UnmarshalJSON(data []byte) (err error) {
|
func (s *ClaimStrings) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
@ -133,10 +137,11 @@ func (s *ClaimStrings) UnmarshalJSON(data []byte) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s ClaimStrings) MarshalJSON() (b []byte, err error) {
|
func (s ClaimStrings) MarshalJSON() (b []byte, err error) {
|
||||||
// This handles a special case in the JWT RFC. If the string array, e.g. used by the "aud" field,
|
// This handles a special case in the JWT RFC. If the string array, e.g.
|
||||||
// only contains one element, it MAY be serialized as a single string. This may or may not be
|
// used by the "aud" field, only contains one element, it MAY be serialized
|
||||||
// desired based on the ecosystem of other JWT library used, so we make it configurable by the
|
// as a single string. This may or may not be desired based on the ecosystem
|
||||||
// variable MarshalSingleStringAsArray.
|
// of other JWT library used, so we make it configurable by the variable
|
||||||
|
// MarshalSingleStringAsArray.
|
||||||
if len(s) == 1 && !MarshalSingleStringAsArray {
|
if len(s) == 1 && !MarshalSingleStringAsArray {
|
||||||
return json.Marshal(s[0])
|
return json.Marshal(s[0])
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,8 @@ import (
|
||||||
// a [Parser] during parsing and can be modified with various parser options.
|
// a [Parser] during parsing and can be modified with various parser options.
|
||||||
//
|
//
|
||||||
// Note: This struct is intentionally not exported (yet) as we want to
|
// Note: This struct is intentionally not exported (yet) as we want to
|
||||||
// internally finalize its API. In the future, we might make it publicly available.
|
// internally finalize its API. In the future, we might make it publicly
|
||||||
|
// available.
|
||||||
type validator struct {
|
type validator struct {
|
||||||
// leeway is an optional leeway that can be provided to account for clock skew.
|
// leeway is an optional leeway that can be provided to account for clock skew.
|
||||||
leeway time.Duration
|
leeway time.Duration
|
||||||
|
|
Loading…
Reference in New Issue