@@ -29,15 +29,19 @@ type (
29
29
// ErrorHandlerWithContext is almost identical to ErrorHandler, but it's passed the current context.
30
30
ErrorHandlerWithContext JWTErrorHandlerWithContext
31
31
32
- // Signing key to validate token. Used as fallback if SigningKeys has length 0.
33
- // Required. This or SigningKeys.
32
+ // Signing key to validate token.
33
+ // This is one of the three options to provide a token validation key.
34
+ // The order of precedence is a user-defined KeyFunc, SigningKeys and SigningKey.
35
+ // Required if neither user-defined KeyFunc nor SigningKeys is provided.
34
36
SigningKey interface {}
35
37
36
38
// Map of signing keys to validate token with kid field usage.
37
- // Required. This or SigningKey.
39
+ // This is one of the three options to provide a token validation key.
40
+ // The order of precedence is a user-defined KeyFunc, SigningKeys and SigningKey.
41
+ // Required if neither user-defined KeyFunc nor SigningKey is provided.
38
42
SigningKeys map [string ]interface {}
39
43
40
- // Signing method, used to check token signing method .
44
+ // Signing method used to check the token's signing algorithm .
41
45
// Optional. Default value HS256.
42
46
SigningMethod string
43
47
@@ -64,7 +68,16 @@ type (
64
68
// Optional. Default value "Bearer".
65
69
AuthScheme string
66
70
67
- keyFunc jwt.Keyfunc
71
+ // KeyFunc defines a user-defined function that supplies the public key for a token validation.
72
+ // The function shall take care of verifying the signing algorithm and selecting the proper key.
73
+ // A user-defined KeyFunc can be useful if tokens are issued by an external party.
74
+ //
75
+ // When a user-defined KeyFunc is provided, SigningKey, SigningKeys, and SigningMethod are ignored.
76
+ // This is one of the three options to provide a token validation key.
77
+ // The order of precedence is a user-defined KeyFunc, SigningKeys and SigningKey.
78
+ // Required if neither SigningKeys nor SigningKey is provided.
79
+ // Default to an internal implementation verifying the signing algorithm and selecting the proper key.
80
+ KeyFunc jwt.Keyfunc
68
81
}
69
82
70
83
// JWTSuccessHandler defines a function which is executed for a valid token.
99
112
TokenLookup : "header:" + echo .HeaderAuthorization ,
100
113
AuthScheme : "Bearer" ,
101
114
Claims : jwt.MapClaims {},
115
+ KeyFunc : nil ,
102
116
}
103
117
)
104
118
@@ -123,7 +137,7 @@ func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
123
137
if config .Skipper == nil {
124
138
config .Skipper = DefaultJWTConfig .Skipper
125
139
}
126
- if config .SigningKey == nil && len (config .SigningKeys ) == 0 {
140
+ if config .SigningKey == nil && len (config .SigningKeys ) == 0 && config . KeyFunc == nil {
127
141
panic ("echo: jwt middleware requires signing key" )
128
142
}
129
143
if config .SigningMethod == "" {
@@ -141,21 +155,8 @@ func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
141
155
if config .AuthScheme == "" {
142
156
config .AuthScheme = DefaultJWTConfig .AuthScheme
143
157
}
144
- config .keyFunc = func (t * jwt.Token ) (interface {}, error ) {
145
- // Check the signing method
146
- if t .Method .Alg () != config .SigningMethod {
147
- return nil , fmt .Errorf ("unexpected jwt signing method=%v" , t .Header ["alg" ])
148
- }
149
- if len (config .SigningKeys ) > 0 {
150
- if kid , ok := t .Header ["kid" ].(string ); ok {
151
- if key , ok := config .SigningKeys [kid ]; ok {
152
- return key , nil
153
- }
154
- }
155
- return nil , fmt .Errorf ("unexpected jwt key id=%v" , t .Header ["kid" ])
156
- }
157
-
158
- return config .SigningKey , nil
158
+ if config .KeyFunc == nil {
159
+ config .KeyFunc = config .defaultKeyFunc
159
160
}
160
161
161
162
// Initialize
@@ -196,11 +197,11 @@ func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
196
197
token := new (jwt.Token )
197
198
// Issue #647, #656
198
199
if _ , ok := config .Claims .(jwt.MapClaims ); ok {
199
- token , err = jwt .Parse (auth , config .keyFunc )
200
+ token , err = jwt .Parse (auth , config .KeyFunc )
200
201
} else {
201
202
t := reflect .ValueOf (config .Claims ).Type ().Elem ()
202
203
claims := reflect .New (t ).Interface ().(jwt.Claims )
203
- token , err = jwt .ParseWithClaims (auth , claims , config .keyFunc )
204
+ token , err = jwt .ParseWithClaims (auth , claims , config .KeyFunc )
204
205
}
205
206
if err == nil && token .Valid {
206
207
// Store user information from token into context.
@@ -225,6 +226,24 @@ func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
225
226
}
226
227
}
227
228
229
+ // defaultKeyFunc returns a signing key of the given token.
230
+ func (config * JWTConfig ) defaultKeyFunc (t * jwt.Token ) (interface {}, error ) {
231
+ // Check the signing method
232
+ if t .Method .Alg () != config .SigningMethod {
233
+ return nil , fmt .Errorf ("unexpected jwt signing method=%v" , t .Header ["alg" ])
234
+ }
235
+ if len (config .SigningKeys ) > 0 {
236
+ if kid , ok := t .Header ["kid" ].(string ); ok {
237
+ if key , ok := config .SigningKeys [kid ]; ok {
238
+ return key , nil
239
+ }
240
+ }
241
+ return nil , fmt .Errorf ("unexpected jwt key id=%v" , t .Header ["kid" ])
242
+ }
243
+
244
+ return config .SigningKey , nil
245
+ }
246
+
228
247
// jwtFromHeader returns a `jwtExtractor` that extracts token from the request header.
229
248
func jwtFromHeader (header string , authScheme string ) jwtExtractor {
230
249
return func (c echo.Context ) (string , error ) {
0 commit comments