1package jwt
2
3import (
4	"bytes"
5	"encoding/json"
6	"fmt"
7	"strings"
8)
9
10type Parser struct {
11	ValidMethods         []string // If populated, only these methods will be considered valid
12	UseJSONNumber        bool     // Use JSON Number format in JSON decoder
13	SkipClaimsValidation bool     // Skip claims validation during token parsing
14}
15
16// Parse, validate, and return a token.
17// keyFunc will receive the parsed token and should return the key for validating.
18// If everything is kosher, err will be nil
19func (p *Parser) Parse(tokenString string, keyFunc Keyfunc) (*Token, error) {
20	return p.ParseWithClaims(tokenString, MapClaims{}, keyFunc)
21}
22
23func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) {
24	parts := strings.Split(tokenString, ".")
25	if len(parts) != 3 {
26		return nil, NewValidationError("token contains an invalid number of segments", ValidationErrorMalformed)
27	}
28
29	var err error
30	token := &Token{Raw: tokenString}
31
32	// parse Header
33	var headerBytes []byte
34	if headerBytes, err = DecodeSegment(parts[0]); err != nil {
35		if strings.HasPrefix(strings.ToLower(tokenString), "bearer ") {
36			return token, NewValidationError("tokenstring should not contain 'bearer '", ValidationErrorMalformed)
37		}
38		return token, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
39	}
40	if err = json.Unmarshal(headerBytes, &token.Header); err != nil {
41		return token, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
42	}
43
44	// parse Claims
45	var claimBytes []byte
46	token.Claims = claims
47
48	if claimBytes, err = DecodeSegment(parts[1]); err != nil {
49		return token, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
50	}
51	dec := json.NewDecoder(bytes.NewBuffer(claimBytes))
52	if p.UseJSONNumber {
53		dec.UseNumber()
54	}
55	// JSON Decode.  Special case for map type to avoid weird pointer behavior
56	if c, ok := token.Claims.(MapClaims); ok {
57		err = dec.Decode(&c)
58	} else {
59		err = dec.Decode(&claims)
60	}
61	// Handle decode error
62	if err != nil {
63		return token, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
64	}
65
66	// Lookup signature method
67	if method, ok := token.Header["alg"].(string); ok {
68		if token.Method = GetSigningMethod(method); token.Method == nil {
69			return token, NewValidationError("signing method (alg) is unavailable.", ValidationErrorUnverifiable)
70		}
71	} else {
72		return token, NewValidationError("signing method (alg) is unspecified.", ValidationErrorUnverifiable)
73	}
74
75	// Verify signing method is in the required set
76	if p.ValidMethods != nil {
77		var signingMethodValid = false
78		var alg = token.Method.Alg()
79		for _, m := range p.ValidMethods {
80			if m == alg {
81				signingMethodValid = true
82				break
83			}
84		}
85		if !signingMethodValid {
86			// signing method is not in the listed set
87			return token, NewValidationError(fmt.Sprintf("signing method %v is invalid", alg), ValidationErrorSignatureInvalid)
88		}
89	}
90
91	// Lookup key
92	var key interface{}
93	if keyFunc == nil {
94		// keyFunc was not provided.  short circuiting validation
95		return token, NewValidationError("no Keyfunc was provided.", ValidationErrorUnverifiable)
96	}
97	if key, err = keyFunc(token); err != nil {
98		// keyFunc returned an error
99		return token, &ValidationError{Inner: err, Errors: ValidationErrorUnverifiable}
100	}
101
102	vErr := &ValidationError{}
103
104	// Validate Claims
105	if !p.SkipClaimsValidation {
106		if err := token.Claims.Valid(); err != nil {
107
108			// If the Claims Valid returned an error, check if it is a validation error,
109			// If it was another error type, create a ValidationError with a generic ClaimsInvalid flag set
110			if e, ok := err.(*ValidationError); !ok {
111				vErr = &ValidationError{Inner: err, Errors: ValidationErrorClaimsInvalid}
112			} else {
113				vErr = e
114			}
115		}
116	}
117
118	// Perform validation
119	token.Signature = parts[2]
120	if err = token.Method.Verify(strings.Join(parts[0:2], "."), token.Signature, key); err != nil {
121		vErr.Inner = err
122		vErr.Errors |= ValidationErrorSignatureInvalid
123	}
124
125	if vErr.valid() {
126		token.Valid = true
127		return token, nil
128	}
129
130	return token, vErr
131}
132