11 jwt "github.com/dgrijalva/jwt-go"
12 "github.com/go-kit/kit/endpoint"
15 type customClaims struct {
16 MyProperty string `json:"my_property"`
20 func (c customClaims) VerifyMyProperty(p string) bool {
21 return subtle.ConstantTimeCompare([]byte(c.MyProperty), []byte(p)) != 0
26 key = []byte("test_signing_key")
27 myProperty = "some value"
28 method = jwt.SigningMethodHS256
29 invalidMethod = jwt.SigningMethodRS256
30 mapClaims = jwt.MapClaims{"user": "go-kit"}
31 standardClaims = jwt.StandardClaims{Audience: "go-kit"}
32 myCustomClaims = customClaims{MyProperty: myProperty, StandardClaims: standardClaims}
33 // Signed tokens generated at https://jwt.io/
34 signedKey = "eyJhbGciOiJIUzI1NiIsImtpZCI6ImtpZCIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiZ28ta2l0In0.14M2VmYyApdSlV_LZ88ajjwuaLeIFplB8JpyNy0A19E"
35 standardSignedKey = "eyJhbGciOiJIUzI1NiIsImtpZCI6ImtpZCIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJnby1raXQifQ.L5ypIJjCOOv3jJ8G5SelaHvR04UJuxmcBN5QW3m_aoY"
36 customSignedKey = "eyJhbGciOiJIUzI1NiIsImtpZCI6ImtpZCIsInR5cCI6IkpXVCJ9.eyJteV9wcm9wZXJ0eSI6InNvbWUgdmFsdWUiLCJhdWQiOiJnby1raXQifQ.s8F-IDrV4WPJUsqr7qfDi-3GRlcKR0SRnkTeUT_U-i0"
37 invalidKey = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.e30.vKVCKto-Wn6rgz3vBdaZaCBGfCBDTXOENSo_X2Gq7qA"
38 malformedKey = "malformed.jwt.token"
41 func signingValidator(t *testing.T, signer endpoint.Endpoint, expectedKey string) {
42 ctx, err := signer(context.Background(), struct{}{})
44 t.Fatalf("Signer returned error: %s", err)
47 token, ok := ctx.(context.Context).Value(JWTTokenContextKey).(string)
49 t.Fatal("Token did not exist in context")
52 if token != expectedKey {
53 t.Fatalf("JWT tokens did not match: expecting %s got %s", expectedKey, token)
57 func TestNewSigner(t *testing.T) {
58 e := func(ctx context.Context, i interface{}) (interface{}, error) { return ctx, nil }
60 signer := NewSigner(kid, key, method, mapClaims)(e)
61 signingValidator(t, signer, signedKey)
63 signer = NewSigner(kid, key, method, standardClaims)(e)
64 signingValidator(t, signer, standardSignedKey)
66 signer = NewSigner(kid, key, method, myCustomClaims)(e)
67 signingValidator(t, signer, customSignedKey)
70 func TestJWTParser(t *testing.T) {
71 e := func(ctx context.Context, i interface{}) (interface{}, error) { return ctx, nil }
73 keys := func(token *jwt.Token) (interface{}, error) {
77 parser := NewParser(keys, method, MapClaimsFactory)(e)
79 // No Token is passed into the parser
80 _, err := parser(context.Background(), struct{}{})
82 t.Error("Parser should have returned an error")
85 if err != ErrTokenContextMissing {
86 t.Errorf("unexpected error returned, expected: %s got: %s", ErrTokenContextMissing, err)
89 // Invalid Token is passed into the parser
90 ctx := context.WithValue(context.Background(), JWTTokenContextKey, invalidKey)
91 _, err = parser(ctx, struct{}{})
93 t.Error("Parser should have returned an error")
96 // Invalid Method is used in the parser
97 badParser := NewParser(keys, invalidMethod, MapClaimsFactory)(e)
98 ctx = context.WithValue(context.Background(), JWTTokenContextKey, signedKey)
99 _, err = badParser(ctx, struct{}{})
101 t.Error("Parser should have returned an error")
104 if err != ErrUnexpectedSigningMethod {
105 t.Errorf("unexpected error returned, expected: %s got: %s", ErrUnexpectedSigningMethod, err)
108 // Invalid key is used in the parser
109 invalidKeys := func(token *jwt.Token) (interface{}, error) {
110 return []byte("bad"), nil
113 badParser = NewParser(invalidKeys, method, MapClaimsFactory)(e)
114 ctx = context.WithValue(context.Background(), JWTTokenContextKey, signedKey)
115 _, err = badParser(ctx, struct{}{})
117 t.Error("Parser should have returned an error")
120 // Correct token is passed into the parser
121 ctx = context.WithValue(context.Background(), JWTTokenContextKey, signedKey)
122 ctx1, err := parser(ctx, struct{}{})
124 t.Fatalf("Parser returned error: %s", err)
127 cl, ok := ctx1.(context.Context).Value(JWTClaimsContextKey).(jwt.MapClaims)
129 t.Fatal("Claims were not passed into context correctly")
132 if cl["user"] != mapClaims["user"] {
133 t.Fatalf("JWT Claims.user did not match: expecting %s got %s", mapClaims["user"], cl["user"])
136 // Test for malformed token error response
137 parser = NewParser(keys, method, StandardClaimsFactory)(e)
138 ctx = context.WithValue(context.Background(), JWTTokenContextKey, malformedKey)
139 ctx1, err = parser(ctx, struct{}{})
140 if want, have := ErrTokenMalformed, err; want != have {
141 t.Fatalf("Expected %+v, got %+v", want, have)
144 // Test for expired token error response
145 parser = NewParser(keys, method, StandardClaimsFactory)(e)
146 expired := jwt.NewWithClaims(method, jwt.StandardClaims{ExpiresAt: time.Now().Unix() - 100})
147 token, err := expired.SignedString(key)
149 t.Fatalf("Unable to Sign Token: %+v", err)
151 ctx = context.WithValue(context.Background(), JWTTokenContextKey, token)
152 ctx1, err = parser(ctx, struct{}{})
153 if want, have := ErrTokenExpired, err; want != have {
154 t.Fatalf("Expected %+v, got %+v", want, have)
157 // Test for not activated token error response
158 parser = NewParser(keys, method, StandardClaimsFactory)(e)
159 notactive := jwt.NewWithClaims(method, jwt.StandardClaims{NotBefore: time.Now().Unix() + 100})
160 token, err = notactive.SignedString(key)
162 t.Fatalf("Unable to Sign Token: %+v", err)
164 ctx = context.WithValue(context.Background(), JWTTokenContextKey, token)
165 ctx1, err = parser(ctx, struct{}{})
166 if want, have := ErrTokenNotActive, err; want != have {
167 t.Fatalf("Expected %+v, got %+v", want, have)
170 // test valid standard claims token
171 parser = NewParser(keys, method, StandardClaimsFactory)(e)
172 ctx = context.WithValue(context.Background(), JWTTokenContextKey, standardSignedKey)
173 ctx1, err = parser(ctx, struct{}{})
175 t.Fatalf("Parser returned error: %s", err)
177 stdCl, ok := ctx1.(context.Context).Value(JWTClaimsContextKey).(*jwt.StandardClaims)
179 t.Fatal("Claims were not passed into context correctly")
181 if !stdCl.VerifyAudience("go-kit", true) {
182 t.Fatalf("JWT jwt.StandardClaims.Audience did not match: expecting %s got %s", standardClaims.Audience, stdCl.Audience)
185 // test valid customized claims token
186 parser = NewParser(keys, method, func() jwt.Claims { return &customClaims{} })(e)
187 ctx = context.WithValue(context.Background(), JWTTokenContextKey, customSignedKey)
188 ctx1, err = parser(ctx, struct{}{})
190 t.Fatalf("Parser returned error: %s", err)
192 custCl, ok := ctx1.(context.Context).Value(JWTClaimsContextKey).(*customClaims)
194 t.Fatal("Claims were not passed into context correctly")
196 if !custCl.VerifyAudience("go-kit", true) {
197 t.Fatalf("JWT customClaims.Audience did not match: expecting %s got %s", standardClaims.Audience, custCl.Audience)
199 if !custCl.VerifyMyProperty(myProperty) {
200 t.Fatalf("JWT customClaims.MyProperty did not match: expecting %s got %s", myProperty, custCl.MyProperty)
204 func TestIssue562(t *testing.T) {
206 kf = func(token *jwt.Token) (interface{}, error) { return []byte("secret"), nil }
207 e = NewParser(kf, jwt.SigningMethodHS256, MapClaimsFactory)(endpoint.Nop)
208 key = JWTTokenContextKey
209 val = "eyJhbGciOiJIUzI1NiIsImtpZCI6ImtpZCIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiZ28ta2l0In0.14M2VmYyApdSlV_LZ88ajjwuaLeIFplB8JpyNy0A19E"
210 ctx = context.WithValue(context.Background(), key, val)
212 wg := sync.WaitGroup{}
213 for i := 0; i < 100; i++ {
217 e(ctx, struct{}{}) // fatal error: concurrent map read and map write