parser.go 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. package jwt
  2. import (
  3. "bytes"
  4. "encoding/base64"
  5. "encoding/json"
  6. "fmt"
  7. "strings"
  8. )
  9. const tokenDelimiter = "."
  10. type Parser struct {
  11. // If populated, only these methods will be considered valid.
  12. validMethods []string
  13. // Use JSON Number format in JSON decoder.
  14. useJSONNumber bool
  15. // Skip claims validation during token parsing.
  16. skipClaimsValidation bool
  17. validator *Validator
  18. decodeStrict bool
  19. decodePaddingAllowed bool
  20. }
  21. // NewParser creates a new Parser with the specified options
  22. func NewParser(options ...ParserOption) *Parser {
  23. p := &Parser{
  24. validator: &Validator{},
  25. }
  26. // Loop through our parsing options and apply them
  27. for _, option := range options {
  28. option(p)
  29. }
  30. return p
  31. }
  32. // Parse parses, validates, verifies the signature and returns the parsed token.
  33. // keyFunc will receive the parsed token and should return the key for validating.
  34. func (p *Parser) Parse(tokenString string, keyFunc Keyfunc) (*Token, error) {
  35. return p.ParseWithClaims(tokenString, MapClaims{}, keyFunc)
  36. }
  37. // ParseWithClaims parses, validates, and verifies like Parse, but supplies a default object implementing the Claims
  38. // interface. This provides default values which can be overridden and allows a caller to use their own type, rather
  39. // than the default MapClaims implementation of Claims.
  40. //
  41. // Note: If you provide a custom claim implementation that embeds one of the standard claims (such as RegisteredClaims),
  42. // make sure that a) you either embed a non-pointer version of the claims or b) if you are using a pointer, allocate the
  43. // proper memory for it before passing in the overall claims, otherwise you might run into a panic.
  44. func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) {
  45. token, parts, err := p.ParseUnverified(tokenString, claims)
  46. if err != nil {
  47. return token, err
  48. }
  49. // Verify signing method is in the required set
  50. if p.validMethods != nil {
  51. var signingMethodValid = false
  52. var alg = token.Method.Alg()
  53. for _, m := range p.validMethods {
  54. if m == alg {
  55. signingMethodValid = true
  56. break
  57. }
  58. }
  59. if !signingMethodValid {
  60. // signing method is not in the listed set
  61. return token, newError(fmt.Sprintf("signing method %v is invalid", alg), ErrTokenSignatureInvalid)
  62. }
  63. }
  64. // Decode signature
  65. token.Signature, err = p.DecodeSegment(parts[2])
  66. if err != nil {
  67. return token, newError("could not base64 decode signature", ErrTokenMalformed, err)
  68. }
  69. text := strings.Join(parts[0:2], ".")
  70. // Lookup key(s)
  71. if keyFunc == nil {
  72. // keyFunc was not provided. short circuiting validation
  73. return token, newError("no keyfunc was provided", ErrTokenUnverifiable)
  74. }
  75. got, err := keyFunc(token)
  76. if err != nil {
  77. return token, newError("error while executing keyfunc", ErrTokenUnverifiable, err)
  78. }
  79. switch have := got.(type) {
  80. case VerificationKeySet:
  81. if len(have.Keys) == 0 {
  82. return token, newError("keyfunc returned empty verification key set", ErrTokenUnverifiable)
  83. }
  84. // Iterate through keys and verify signature, skipping the rest when a match is found.
  85. // Return the last error if no match is found.
  86. for _, key := range have.Keys {
  87. if err = token.Method.Verify(text, token.Signature, key); err == nil {
  88. break
  89. }
  90. }
  91. default:
  92. err = token.Method.Verify(text, token.Signature, have)
  93. }
  94. if err != nil {
  95. return token, newError("", ErrTokenSignatureInvalid, err)
  96. }
  97. // Validate Claims
  98. if !p.skipClaimsValidation {
  99. // Make sure we have at least a default validator
  100. if p.validator == nil {
  101. p.validator = NewValidator()
  102. }
  103. if err := p.validator.Validate(claims); err != nil {
  104. return token, newError("", ErrTokenInvalidClaims, err)
  105. }
  106. }
  107. // No errors so far, token is valid.
  108. token.Valid = true
  109. return token, nil
  110. }
  111. // ParseUnverified parses the token but doesn't validate the signature.
  112. //
  113. // WARNING: Don't use this method unless you know what you're doing.
  114. //
  115. // It's only ever useful in cases where you know the signature is valid (since it has already
  116. // been or will be checked elsewhere in the stack) and you want to extract values from it.
  117. func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Token, parts []string, err error) {
  118. var ok bool
  119. parts, ok = splitToken(tokenString)
  120. if !ok {
  121. return nil, nil, newError("token contains an invalid number of segments", ErrTokenMalformed)
  122. }
  123. token = &Token{Raw: tokenString}
  124. // parse Header
  125. var headerBytes []byte
  126. if headerBytes, err = p.DecodeSegment(parts[0]); err != nil {
  127. return token, parts, newError("could not base64 decode header", ErrTokenMalformed, err)
  128. }
  129. if err = json.Unmarshal(headerBytes, &token.Header); err != nil {
  130. return token, parts, newError("could not JSON decode header", ErrTokenMalformed, err)
  131. }
  132. // parse Claims
  133. token.Claims = claims
  134. claimBytes, err := p.DecodeSegment(parts[1])
  135. if err != nil {
  136. return token, parts, newError("could not base64 decode claim", ErrTokenMalformed, err)
  137. }
  138. // If `useJSONNumber` is enabled then we must use *json.Decoder to decode
  139. // the claims. However, this comes with a performance penalty so only use
  140. // it if we must and, otherwise, simple use json.Unmarshal.
  141. if !p.useJSONNumber {
  142. // JSON Unmarshal. Special case for map type to avoid weird pointer behavior.
  143. if c, ok := token.Claims.(MapClaims); ok {
  144. err = json.Unmarshal(claimBytes, &c)
  145. } else {
  146. err = json.Unmarshal(claimBytes, &claims)
  147. }
  148. } else {
  149. dec := json.NewDecoder(bytes.NewBuffer(claimBytes))
  150. dec.UseNumber()
  151. // JSON Decode. Special case for map type to avoid weird pointer behavior.
  152. if c, ok := token.Claims.(MapClaims); ok {
  153. err = dec.Decode(&c)
  154. } else {
  155. err = dec.Decode(&claims)
  156. }
  157. }
  158. if err != nil {
  159. return token, parts, newError("could not JSON decode claim", ErrTokenMalformed, err)
  160. }
  161. // Lookup signature method
  162. if method, ok := token.Header["alg"].(string); ok {
  163. if token.Method = GetSigningMethod(method); token.Method == nil {
  164. return token, parts, newError("signing method (alg) is unavailable", ErrTokenUnverifiable)
  165. }
  166. } else {
  167. return token, parts, newError("signing method (alg) is unspecified", ErrTokenUnverifiable)
  168. }
  169. return token, parts, nil
  170. }
  171. // splitToken splits a token string into three parts: header, claims, and signature. It will only
  172. // return true if the token contains exactly two delimiters and three parts. In all other cases, it
  173. // will return nil parts and false.
  174. func splitToken(token string) ([]string, bool) {
  175. parts := make([]string, 3)
  176. header, remain, ok := strings.Cut(token, tokenDelimiter)
  177. if !ok {
  178. return nil, false
  179. }
  180. parts[0] = header
  181. claims, remain, ok := strings.Cut(remain, tokenDelimiter)
  182. if !ok {
  183. return nil, false
  184. }
  185. parts[1] = claims
  186. // One more cut to ensure the signature is the last part of the token and there are no more
  187. // delimiters. This avoids an issue where malicious input could contain additional delimiters
  188. // causing unecessary overhead parsing tokens.
  189. signature, _, unexpected := strings.Cut(remain, tokenDelimiter)
  190. if unexpected {
  191. return nil, false
  192. }
  193. parts[2] = signature
  194. return parts, true
  195. }
  196. // DecodeSegment decodes a JWT specific base64url encoding. This function will
  197. // take into account whether the [Parser] is configured with additional options,
  198. // such as [WithStrictDecoding] or [WithPaddingAllowed].
  199. func (p *Parser) DecodeSegment(seg string) ([]byte, error) {
  200. encoding := base64.RawURLEncoding
  201. if p.decodePaddingAllowed {
  202. if l := len(seg) % 4; l > 0 {
  203. seg += strings.Repeat("=", 4-l)
  204. }
  205. encoding = base64.URLEncoding
  206. }
  207. if p.decodeStrict {
  208. encoding = encoding.Strict()
  209. }
  210. return encoding.DecodeString(seg)
  211. }
  212. // Parse parses, validates, verifies the signature and returns the parsed token.
  213. // keyFunc will receive the parsed token and should return the cryptographic key
  214. // for verifying the signature. The caller is strongly encouraged to set the
  215. // WithValidMethods option to validate the 'alg' claim in the token matches the
  216. // expected algorithm. For more details about the importance of validating the
  217. // 'alg' claim, see
  218. // https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/
  219. func Parse(tokenString string, keyFunc Keyfunc, options ...ParserOption) (*Token, error) {
  220. return NewParser(options...).Parse(tokenString, keyFunc)
  221. }
  222. // ParseWithClaims is a shortcut for NewParser().ParseWithClaims().
  223. //
  224. // Note: If you provide a custom claim implementation that embeds one of the
  225. // standard claims (such as RegisteredClaims), make sure that a) you either
  226. // embed a non-pointer version of the claims or b) if you are using a pointer,
  227. // allocate the proper memory for it before passing in the overall claims,
  228. // otherwise you might run into a panic.
  229. func ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc, options ...ParserOption) (*Token, error) {
  230. return NewParser(options...).ParseWithClaims(tokenString, claims, keyFunc)
  231. }