diff --git a/.travis.yml b/.travis.yml index dfe286eb..d6089146 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,3 +3,5 @@ language: go go: - 1.3.3 - 1.4.2 + - 1.5 + - tip diff --git a/README.md b/README.md index 0245f172..5b302693 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,12 @@ Parsing and verifying tokens is pretty straight forward. You pass in the token tokenString, err := token.SignedString(mySigningKey) ``` +## Extensions + +This library publishes all the necessary components for adding your own signing methods. Simply implement the `SigningMethod` interface and register a factory method using `RegisterSigningMethod`. + +Here's an example of an extension that integrates with the Google App Engine signing tools: https://github.com/someone1/gcp-jwt-go + ## Project Status & Versioning This library is considered production ready. Feedback and feature requests are appreciated. The API should be considered stable. There should be very few backwards-incompatible changes outside of major version updates (and only with good reason). diff --git a/cmd/jwt/app.go b/cmd/jwt/app.go index e8225dcf..4b74a46a 100644 --- a/cmd/jwt/app.go +++ b/cmd/jwt/app.go @@ -14,6 +14,7 @@ import ( "io/ioutil" "os" "regexp" + "strings" "github.com/dgrijalva/jwt-go" ) @@ -116,7 +117,14 @@ func verifyToken() error { // Parse the token. Load the key from command line option token, err := jwt.Parse(string(tokData), func(t *jwt.Token) (interface{}, error) { - return loadData(*flagKey) + data, err := loadData(*flagKey) + if err != nil { + return nil, err + } + if isEs() { + return jwt.ParseECPublicKeyFromPEM(data) + } + return data, nil }) // Print some debug data @@ -161,7 +169,8 @@ func signToken() error { } // get the key - keyData, err := loadData(*flagKey) + var key interface{} + key, err = loadData(*flagKey) if err != nil { return fmt.Errorf("Couldn't read key: %v", err) } @@ -175,7 +184,18 @@ func signToken() error { // create a new token token := jwt.NewWithClaims(alg, claims) - if out, err := token.SignedString(keyData); err == nil { + if isEs() { + if k, ok := key.([]byte); !ok { + return fmt.Errorf("Couldn't convert key data to key") + } else { + key, err = jwt.ParseECPrivateKeyFromPEM(k) + if err != nil { + return err + } + } + } + + if out, err := token.SignedString(key); err == nil { fmt.Println(out) } else { return fmt.Errorf("Error signing token: %v", err) @@ -183,3 +203,7 @@ func signToken() error { return nil } + +func isEs() bool { + return strings.HasPrefix(*flagAlg, "ES") +} diff --git a/ecdsa.go b/ecdsa.go index 9cd538ff..0518ed10 100644 --- a/ecdsa.go +++ b/ecdsa.go @@ -4,7 +4,6 @@ import ( "crypto" "crypto/ecdsa" "crypto/rand" - "encoding/asn1" "errors" "math/big" ) @@ -16,14 +15,10 @@ var ( // Implements the ECDSA family of signing methods signing methods type SigningMethodECDSA struct { - Name string - Hash crypto.Hash -} - -// Marshalling structure for r, s EC point -type ECPoint struct { - R *big.Int - S *big.Int + Name string + Hash crypto.Hash + KeySize int + CurveBits int } // Specific instances for EC256 and company @@ -35,19 +30,19 @@ var ( func init() { // ES256 - SigningMethodES256 = &SigningMethodECDSA{"ES256", crypto.SHA256} + SigningMethodES256 = &SigningMethodECDSA{"ES256", crypto.SHA256, 32, 256} RegisterSigningMethod(SigningMethodES256.Alg(), func() SigningMethod { return SigningMethodES256 }) // ES384 - SigningMethodES384 = &SigningMethodECDSA{"ES384", crypto.SHA384} + SigningMethodES384 = &SigningMethodECDSA{"ES384", crypto.SHA384, 48, 384} RegisterSigningMethod(SigningMethodES384.Alg(), func() SigningMethod { return SigningMethodES384 }) // ES512 - SigningMethodES512 = &SigningMethodECDSA{"ES512", crypto.SHA512} + SigningMethodES512 = &SigningMethodECDSA{"ES512", crypto.SHA512, 66, 521} RegisterSigningMethod(SigningMethodES512.Alg(), func() SigningMethod { return SigningMethodES512 }) @@ -77,12 +72,13 @@ func (m *SigningMethodECDSA) Verify(signingString, signature string, key interfa return ErrInvalidKey } - // Unmarshal asn1 ECPoint - var ecpoint = new(ECPoint) - if _, err := asn1.Unmarshal(sig, ecpoint); err != nil { - return err + if len(sig) != 2*m.KeySize { + return ErrECDSAVerification } + r := big.NewInt(0).SetBytes(sig[:m.KeySize]) + s := big.NewInt(0).SetBytes(sig[m.KeySize:]) + // Create hasher if !m.Hash.Available() { return ErrHashUnavailable @@ -91,7 +87,7 @@ func (m *SigningMethodECDSA) Verify(signingString, signature string, key interfa hasher.Write([]byte(signingString)) // Verify the signature - if verifystatus := ecdsa.Verify(ecdsaKey, hasher.Sum(nil), ecpoint.R, ecpoint.S); verifystatus == true { + if verifystatus := ecdsa.Verify(ecdsaKey, hasher.Sum(nil), r, s); verifystatus == true { return nil } else { return ErrECDSAVerification @@ -120,16 +116,31 @@ func (m *SigningMethodECDSA) Sign(signingString string, key interface{}) (string // Sign the string and return r, s if r, s, err := ecdsa.Sign(rand.Reader, ecdsaKey, hasher.Sum(nil)); err == nil { - // asn1 marhsal r, s using ecPoint as the structure - var ecpoint = new(ECPoint) - ecpoint.R = r - ecpoint.S = s - - if signature, err := asn1.Marshal(*ecpoint); err != nil { - return "", err - } else { - return EncodeSegment(signature), nil + curveBits := ecdsaKey.Curve.Params().BitSize + + if m.CurveBits != curveBits { + return "", ErrInvalidKey } + + keyBytes := curveBits / 8 + if curveBits%8 > 0 { + keyBytes += 1 + } + + // We serialize the outpus (r and s) into big-endian byte arrays and pad + // them with zeros on the left to make sure the sizes work out. Both arrays + // must be keyBytes long, and the output must be 2*keyBytes long. + rBytes := r.Bytes() + rBytesPadded := make([]byte, keyBytes) + copy(rBytesPadded[keyBytes-len(rBytes):], rBytes) + + sBytes := s.Bytes() + sBytesPadded := make([]byte, keyBytes) + copy(sBytesPadded[keyBytes-len(sBytes):], sBytes) + + out := append(rBytesPadded, sBytesPadded...) + + return EncodeSegment(out), nil } else { return "", err } diff --git a/ecdsa_test.go b/ecdsa_test.go index 98e3e5ed..753047b1 100644 --- a/ecdsa_test.go +++ b/ecdsa_test.go @@ -20,7 +20,7 @@ var ecdsaTestData = []struct { { "Basic ES256", map[string]string{"private": "test/ec256-private.pem", "public": "test/ec256-public.pem"}, - "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.MEQCIHoSJnmGlPaVQDqacx_2XlXEhhqtWceVopjomc2PJLtdAiAUTeGPoNYxZw0z8mgOnnIcjoxRuNDVZvybRZF3wR1l8w", + "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJmb28iOiJiYXIifQ.feG39E-bn8HXAKhzDZq7yEAPWYDhZlwTn3sePJnU9VrGMmwdXAIEyoOnrjreYlVM_Z4N13eK9-TmMTWyfKJtHQ", "ES256", map[string]interface{}{"foo": "bar"}, true, @@ -28,7 +28,7 @@ var ecdsaTestData = []struct { { "Basic ES384", map[string]string{"private": "test/ec384-private.pem", "public": "test/ec384-public.pem"}, - "eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.MGUCMQCHBr61FXDuFY9xUhyp8iWQAuBIaSgaf1z2j_8XrKcCfzTPzoSa3SZKq-m3L492xe8CMG3kafRMeuaN5Aw8ZJxmOLhkTo4D3-LaGzcaUWINvWvkwFMl7dMC863s0gov6xvXuA", + "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzM4NCJ9.eyJmb28iOiJiYXIifQ.ngAfKMbJUh0WWubSIYe5GMsA-aHNKwFbJk_wq3lq23aPp8H2anb1rRILIzVR0gUf4a8WzDtrzmiikuPWyCS6CN4-PwdgTk-5nehC7JXqlaBZU05p3toM3nWCwm_LXcld", "ES384", map[string]interface{}{"foo": "bar"}, true, @@ -36,7 +36,7 @@ var ecdsaTestData = []struct { { "Basic ES512", map[string]string{"private": "test/ec512-private.pem", "public": "test/ec512-public.pem"}, - "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.MIGIAkIAmVKjdJE5lG1byOFgZZVTeNDRp6E7SNvUj0UrvpzoBH6nrleWVTcwfHzbwWuooNpPADDSFR_Ql3ze-Vwwi8hBqQsCQgHn-ZooL8zegkOVeEEsqd7WHWdhb8UekFCYw3X8JnNP-D3wvZQ1-tkkHakt5gZ2-xO29TxfSPun4ViGkMYa7Q4N-Q", + "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzUxMiJ9.eyJmb28iOiJiYXIifQ.AAU0TvGQOcdg2OvrwY73NHKgfk26UDekh9Prz-L_iWuTBIBqOFCWwwLsRiHB1JOddfKAls5do1W0jR_F30JpVd-6AJeTjGKA4C1A1H6gIKwRY0o_tFDIydZCl_lMBMeG5VNFAjO86-WCSKwc3hqaGkq1MugPRq_qrF9AVbuEB4JPLyL5", "ES512", map[string]interface{}{"foo": "bar"}, true, diff --git a/hmac.go b/hmac.go index 402ff085..192e625f 100644 --- a/hmac.go +++ b/hmac.go @@ -44,26 +44,36 @@ func (m *SigningMethodHMAC) Alg() string { return m.Name } +// Verify the signature of HSXXX tokens. Returns nil if the signature is valid. func (m *SigningMethodHMAC) Verify(signingString, signature string, key interface{}) error { - if keyBytes, ok := key.([]byte); ok { - var sig []byte - var err error - if sig, err = DecodeSegment(signature); err == nil { - if !m.Hash.Available() { - return ErrHashUnavailable - } - - hasher := hmac.New(m.Hash.New, keyBytes) - hasher.Write([]byte(signingString)) - - if !hmac.Equal(sig, hasher.Sum(nil)) { - err = ErrSignatureInvalid - } - } + // Verify the key is the right type + keyBytes, ok := key.([]byte) + if !ok { + return ErrInvalidKey + } + + // Decode signature, for comparison + sig, err := DecodeSegment(signature) + if err != nil { return err } - return ErrInvalidKey + // Can we use the specified hashing method? + if !m.Hash.Available() { + return ErrHashUnavailable + } + + // This signing method is symmetric, so we validate the signature + // by reproducing the signature from the signing string and key, then + // comparing that against the provided signature. + hasher := hmac.New(m.Hash.New, keyBytes) + hasher.Write([]byte(signingString)) + if !hmac.Equal(sig, hasher.Sum(nil)) { + return ErrSignatureInvalid + } + + // No validation errors. Signature is good. + return nil } // Implements the Sign method from SigningMethod for this signing method. diff --git a/parser.go b/parser.go new file mode 100644 index 00000000..e6c94c2c --- /dev/null +++ b/parser.go @@ -0,0 +1,118 @@ +package jwt + +import ( + "bytes" + "encoding/json" + "fmt" + "strings" +) + +type Parser struct { + ValidMethods []string // If populated, only these methods will be considered valid + UseJSONNumber bool // Use JSON Number format in JSON decoder +} + +// Parse, validate, and return a token. +// keyFunc will receive the parsed token and should return the key for validating. +// If everything is kosher, err will be nil +func (p *Parser) Parse(tokenString string, keyFunc Keyfunc) (*Token, error) { + return p.ParseWithClaims(tokenString, keyFunc, &MapClaims{}) +} + +func (p *Parser) ParseWithClaims(tokenString string, keyFunc Keyfunc, claims Claims) (*Token, error) { + parts := strings.Split(tokenString, ".") + if len(parts) != 3 { + return nil, &ValidationError{err: "token contains an invalid number of segments", Errors: ValidationErrorMalformed} + } + + var err error + token := &Token{Raw: tokenString} + + // parse Header + var headerBytes []byte + if headerBytes, err = DecodeSegment(parts[0]); err != nil { + return token, &ValidationError{err: err.Error(), Errors: ValidationErrorMalformed} + } + if err = json.Unmarshal(headerBytes, &token.Header); err != nil { + return token, &ValidationError{err: err.Error(), Errors: ValidationErrorMalformed} + } + + // parse Claims + var claimBytes []byte + + if claimBytes, err = DecodeSegment(parts[1]); err != nil { + return token, &ValidationError{err: err.Error(), Errors: ValidationErrorMalformed} + } + dec := json.NewDecoder(bytes.NewBuffer(claimBytes)) + if p.UseJSONNumber { + dec.UseNumber() + } + if err = dec.Decode(&claims); err != nil { + return token, &ValidationError{err: err.Error(), Errors: ValidationErrorMalformed} + } + + token.Claims = claims + + // Lookup signature method + if method, ok := token.Header["alg"].(string); ok { + if token.Method = GetSigningMethod(method); token.Method == nil { + return token, &ValidationError{err: "signing method (alg) is unavailable.", Errors: ValidationErrorUnverifiable} + } + } else { + return token, &ValidationError{err: "signing method (alg) is unspecified.", Errors: ValidationErrorUnverifiable} + } + + // Verify signing method is in the required set + if p.ValidMethods != nil { + var signingMethodValid = false + var alg = token.Method.Alg() + for _, m := range p.ValidMethods { + if m == alg { + signingMethodValid = true + break + } + } + if !signingMethodValid { + // signing method is not in the listed set + return token, &ValidationError{err: fmt.Sprintf("signing method %v is invalid", alg), Errors: ValidationErrorSignatureInvalid} + } + } + + // Lookup key + var key interface{} + if keyFunc == nil { + // keyFunc was not provided. short circuiting validation + return token, &ValidationError{err: "no Keyfunc was provided.", Errors: ValidationErrorUnverifiable} + } + if key, err = keyFunc(token); err != nil { + // keyFunc returned an error + return token, &ValidationError{err: err.Error(), Errors: ValidationErrorUnverifiable} + } + + vErr := &ValidationError{} + + // Validate Claims + if err := token.Claims.Valid(); err != nil { + + // If the Claims Valid returned an error, check if it is a validation error, + // If it was another error type, create a ValidationError with a generic ClaimsInvalid flag set + if e, ok := err.(*ValidationError); !ok { + vErr = &ValidationError{err: err.Error(), Errors: ValidationErrorClaimsInvalid} + } else { + vErr = e + } + } + + // Perform validation + if err = token.Method.Verify(strings.Join(parts[0:2], "."), parts[2], key); err != nil { + vErr.err = err.Error() + vErr.Errors |= ValidationErrorSignatureInvalid + } + + if vErr.valid() { + token.Valid = true + return token, nil + } + + return token, vErr +} diff --git a/jwt_test.go b/parser_test.go similarity index 83% rename from jwt_test.go rename to parser_test.go index 66c148a7..c75b5d63 100644 --- a/jwt_test.go +++ b/parser_test.go @@ -2,6 +2,7 @@ package jwt_test import ( "crypto/rsa" + "encoding/json" "fmt" "io/ioutil" "net/http" @@ -27,6 +28,7 @@ var jwtTestData = []struct { claims jwt.MapClaims valid bool errors uint32 + parser *jwt.Parser }{ { "basic", @@ -35,6 +37,7 @@ var jwtTestData = []struct { jwt.MapClaims{"foo": "bar"}, true, 0, + nil, }, { "basic expired", @@ -43,6 +46,7 @@ var jwtTestData = []struct { jwt.MapClaims{"foo": "bar", "exp": float64(time.Now().Unix() - 100)}, false, jwt.ValidationErrorExpired, + nil, }, { "basic nbf", @@ -51,6 +55,7 @@ var jwtTestData = []struct { jwt.MapClaims{"foo": "bar", "nbf": float64(time.Now().Unix() + 100)}, false, jwt.ValidationErrorNotValidYet, + nil, }, { "expired and nbf", @@ -59,6 +64,7 @@ var jwtTestData = []struct { jwt.MapClaims{"foo": "bar", "nbf": float64(time.Now().Unix() + 100), "exp": float64(time.Now().Unix() - 100)}, false, jwt.ValidationErrorNotValidYet | jwt.ValidationErrorExpired, + nil, }, { "basic invalid", @@ -67,6 +73,7 @@ var jwtTestData = []struct { jwt.MapClaims{"foo": "bar"}, false, jwt.ValidationErrorSignatureInvalid, + nil, }, { "basic nokeyfunc", @@ -75,6 +82,7 @@ var jwtTestData = []struct { jwt.MapClaims{"foo": "bar"}, false, jwt.ValidationErrorUnverifiable, + nil, }, { "basic nokey", @@ -83,6 +91,7 @@ var jwtTestData = []struct { jwt.MapClaims{"foo": "bar"}, false, jwt.ValidationErrorSignatureInvalid, + nil, }, { "basic errorkey", @@ -91,6 +100,34 @@ var jwtTestData = []struct { jwt.MapClaims{"foo": "bar"}, false, jwt.ValidationErrorUnverifiable, + nil, + }, + { + "invalid signing method", + "", + defaultKeyFunc, + map[string]interface{}{"foo": "bar"}, + false, + jwt.ValidationErrorSignatureInvalid, + &jwt.Parser{ValidMethods: []string{"HS256"}}, + }, + { + "valid signing method", + "", + defaultKeyFunc, + map[string]interface{}{"foo": "bar"}, + true, + 0, + &jwt.Parser{ValidMethods: []string{"RS256", "HS256"}}, + }, + { + "JSON Number", + "", + defaultKeyFunc, + map[string]interface{}{"foo": json.Number("123.4")}, + true, + 0, + &jwt.Parser{UseJSONNumber: true}, }, } @@ -124,13 +161,19 @@ func makeSample(c jwt.MapClaims) string { return s } -func TestJWT(t *testing.T) { +func TestParser_Parse(t *testing.T) { for _, data := range jwtTestData { if data.tokenString == "" { data.tokenString = makeSample(data.claims) } - token, err := jwt.ParseWithClaims(data.tokenString, data.keyfunc, &jwt.MapClaims{}) + var token *jwt.Token + var err error + if data.parser != nil { + token, err = data.parser.Parse(data.tokenString, data.keyfunc) + } else { + token, err = jwt.Parse(data.tokenString, data.keyfunc) + } if !reflect.DeepEqual(&data.claims, token.Claims) { t.Errorf("[%v] Claims mismatch. Expecting: %v Got: %v", data.name, data.claims, token.Claims) @@ -149,8 +192,8 @@ func TestJWT(t *testing.T) { t.Errorf("[%v] Expecting error. Didn't get one.", data.name) } else { // compare the bitfield part of the error - if err.(*jwt.ValidationError).Errors != data.errors { - t.Errorf("[%v] Errors don't match expectation", data.name) + if e := err.(*jwt.ValidationError).Errors; e != data.errors { + t.Errorf("[%v] Errors don't match expectation. %v != %v", data.name, e, data.errors) } } @@ -161,6 +204,12 @@ func TestJWT(t *testing.T) { func TestParseRequest(t *testing.T) { // Bearer token request for _, data := range jwtTestData { + // FIXME: custom parsers are not supported by this helper. skip tests that require them + if data.parser != nil { + t.Logf("Skipping [%v]. Custom parsers are not supported by ParseRequest", data.name) + continue + } + if data.tokenString == "" { data.tokenString = makeSample(data.claims) } diff --git a/rsa_pss.go b/rsa_pss.go index 0cedd5ee..b5b70735 100644 --- a/rsa_pss.go +++ b/rsa_pss.go @@ -69,7 +69,7 @@ func init() { } // Implements the Verify method from SigningMethod -// For this verify method, key must be an rsa.PrivateKey struct +// For this verify method, key must be an rsa.PublicKey struct func (m *SigningMethodRSAPSS) Verify(signingString, signature string, key interface{}) error { var err error @@ -98,7 +98,7 @@ func (m *SigningMethodRSAPSS) Verify(signingString, signature string, key interf } // Implements the Sign method from SigningMethod -// For this signing method, key must be an rsa.PublicKey struct +// For this signing method, key must be an rsa.PrivateKey struct func (m *SigningMethodRSAPSS) Sign(signingString string, key interface{}) (string, error) { var rsaKey *rsa.PrivateKey diff --git a/signing_method.go b/signing_method.go index 109dd0f5..12cf0f3d 100644 --- a/signing_method.go +++ b/signing_method.go @@ -2,11 +2,11 @@ package jwt var signingMethods = map[string]func() SigningMethod{} -// Signing method +// Implement SigningMethod to add new methods for signing or verifying tokens. type SigningMethod interface { - Verify(signingString, signature string, key interface{}) error - Sign(signingString string, key interface{}) (string, error) - Alg() string + Verify(signingString, signature string, key interface{}) error // Returns nil if signature is valid + Sign(signingString string, key interface{}) (string, error) // Returns encoded signature or error + Alg() string // returns the alg identifier for this method (example: 'HS256') } // Register the "alg" name and a factory function for signing method. diff --git a/jwt.go b/token.go similarity index 62% rename from jwt.go rename to token.go index ed1b00b2..aba32c88 100644 --- a/jwt.go +++ b/token.go @@ -87,88 +87,11 @@ func (t *Token) SigningString() (string, error) { // keyFunc will receive the parsed token and should return the key for validating. // If everything is kosher, err will be nil func Parse(tokenString string, keyFunc Keyfunc) (*Token, error) { - return ParseWithClaims(tokenString, keyFunc, MapClaims{}) + return new(Parser).Parse(tokenString, keyFunc) } func ParseWithClaims(tokenString string, keyFunc Keyfunc, claims Claims) (*Token, error) { - parts := strings.Split(tokenString, ".") - if len(parts) != 3 { - return nil, &ValidationError{err: "token contains an invalid number of segments", Errors: ValidationErrorMalformed} - } - - var err error - token := &Token{ - Raw: tokenString, - } - - // parse Header - var headerBytes []byte - if headerBytes, err = DecodeSegment(parts[0]); err != nil { - return token, &ValidationError{err: err.Error(), Errors: ValidationErrorMalformed} - } - if err = json.Unmarshal(headerBytes, &token.Header); err != nil { - return token, &ValidationError{err: err.Error(), Errors: ValidationErrorMalformed} - } - - // parse Claims - var claimBytes []byte - - if claimBytes, err = DecodeSegment(parts[1]); err != nil { - return token, &ValidationError{err: err.Error(), Errors: ValidationErrorMalformed} - } - - if err = json.Unmarshal(claimBytes, &claims); err != nil { - return token, &ValidationError{err: err.Error(), Errors: ValidationErrorMalformed} - } - - token.Claims = claims - - // Lookup signature method - if method, ok := token.Header["alg"].(string); ok { - if token.Method = GetSigningMethod(method); token.Method == nil { - return token, &ValidationError{err: "signing method (alg) is unavailable.", Errors: ValidationErrorUnverifiable} - } - } else { - return token, &ValidationError{err: "signing method (alg) is unspecified.", Errors: ValidationErrorUnverifiable} - } - - // Lookup key - var key interface{} - if keyFunc == nil { - // keyFunc was not provided. short circuiting validation - return token, &ValidationError{err: "no Keyfunc was provided.", Errors: ValidationErrorUnverifiable} - } - if key, err = keyFunc(token); err != nil { - // keyFunc returned an error - return token, &ValidationError{err: err.Error(), Errors: ValidationErrorUnverifiable} - } - - vErr := &ValidationError{} - - // Validate Claims - if err := token.Claims.Valid(); err != nil { - - // If the Claims Valid returned an error, check if it is a validation error, - // If it was another error type, create a ValidationError with a generic ClaimsInvalid flag set - if e, ok := err.(*ValidationError); !ok { - vErr = &ValidationError{err: err.Error(), Errors: ValidationErrorClaimsInvalid} - } else { - vErr = e - } - } - - // Perform validation - if err = token.Method.Verify(strings.Join(parts[0:2], "."), parts[2], key); err != nil { - vErr.err = err.Error() - vErr.Errors |= ValidationErrorSignatureInvalid - } - - if vErr.valid() { - token.Valid = true - return token, nil - } - - return token, vErr + return new(Parser).ParseWithClaims(tokenString, keyFunc, claims) } // Try to find the token in an http.Request. @@ -176,7 +99,7 @@ func ParseWithClaims(tokenString string, keyFunc Keyfunc, claims Claims) (*Token // Currently, it looks in the Authorization header as well as // looking for an 'access_token' request parameter in req.Form. func ParseFromRequest(req *http.Request, keyFunc Keyfunc) (token *Token, err error) { - return ParseFromRequestWithClaims(req, keyFunc, MapClaims{}) + return ParseFromRequestWithClaims(req, keyFunc, &MapClaims{}) } func ParseFromRequestWithClaims(req *http.Request, keyFunc Keyfunc, claims Claims) (token *Token, err error) {