6
6
7
7
var InvalidArgumentError = require ( '../errors/invalid-argument-error' ) ;
8
8
var InvalidClientError = require ( '../errors/invalid-client-error' ) ;
9
+ var InvalidTokenError = require ( '../errors/invalid-token-error' ) ;
9
10
var InvalidRequestError = require ( '../errors/invalid-request-error' ) ;
10
11
var OAuthError = require ( '../errors/oauth-error' ) ;
11
12
var Promise = require ( 'bluebird' ) ;
@@ -34,6 +35,10 @@ function RevokeHandler(options) {
34
35
throw new InvalidArgumentError ( 'Invalid argument: model does not implement `getRefreshToken()`' ) ;
35
36
}
36
37
38
+ if ( ! options . model . getAccessToken ) {
39
+ throw new InvalidArgumentError ( 'Invalid argument: model does not implement `getAccessToken()`' ) ;
40
+ }
41
+
37
42
if ( ! options . model . revokeToken ) {
38
43
throw new InvalidArgumentError ( 'Invalid argument: model does not implement `revokeToken()`' ) ;
39
44
}
@@ -66,40 +71,57 @@ RevokeHandler.prototype.handle = function(request, response) {
66
71
. then ( function ( ) {
67
72
return this . getClient ( request , response ) ;
68
73
} )
69
- . then ( function ( client ) {
74
+ . then ( function ( client ) {
70
75
return this . handleRevokeToken ( request , client ) ;
71
76
} )
72
- . then ( function ( ) {
77
+ . catch ( function ( e ) {
78
+ if ( ! ( e instanceof OAuthError ) ) {
79
+ e = new ServerError ( e ) ;
80
+ }
73
81
/**
74
82
* All necessary information is conveyed in the response code.
75
83
*
76
- * @see https://tools.ietf.org/html/rfc7009#section-2.1
84
+ * Note: invalid tokens do not cause an error response since the client
85
+ * cannot handle such an error in a reasonable way. Moreover, the
86
+ * purpose of the revocation request, invalidating the particular token,
87
+ * is already achieved.
88
+ * @see https://tools.ietf.org/html/rfc7009#section-2.2
77
89
*/
78
- return { } ;
79
- } )
80
- . catch ( function ( e ) {
81
- if ( ! ( e instanceof OAuthError ) ) {
82
- e = new ServerError ( e ) ;
90
+ if ( ! ( e instanceof InvalidTokenError ) ) {
91
+ this . updateErrorResponse ( response , e ) ;
83
92
}
84
93
85
- this . updateErrorResponse ( response , e ) ;
86
-
87
94
throw e ;
88
95
} ) ;
89
96
} ;
90
97
91
98
/**
92
- * Handle revoke token
99
+ * Revoke a refresh or access token.
100
+ *
101
+ * Handle the revoking of refresh tokens, and access tokens if supported / desirable
102
+ * RFC7009 specifies that "If the server is unable to locate the token using
103
+ * the given hint, it MUST extend its search across all of its supported token types"
93
104
*/
94
105
95
106
RevokeHandler . prototype . handleRevokeToken = function ( request , client ) {
96
107
return Promise . bind ( this )
97
108
. then ( function ( ) {
98
109
return this . getTokenFromRequest ( request ) ;
99
- } ) . then ( function ( token ) {
100
- return this . getRefreshToken ( token , client ) ;
101
- } ) . tap ( function ( token ) {
102
- return this . revokeToken ( token ) ;
110
+ } )
111
+ . then ( function ( token ) {
112
+ return Promise . any ( [
113
+ this . getAccessToken ( token , client ) ,
114
+ this . getRefreshToken ( token , client )
115
+ ] )
116
+ . catch ( Promise . AggregateError , function ( err ) {
117
+ err . forEach ( function ( e ) {
118
+ throw e ;
119
+ } ) ;
120
+ } )
121
+ . bind ( this )
122
+ . tap ( function ( token ) {
123
+ return this . revokeToken ( token ) ;
124
+ } ) ;
103
125
} ) ;
104
126
} ;
105
127
@@ -196,17 +218,15 @@ RevokeHandler.prototype.getTokenFromRequest = function(request) {
196
218
return bodyToken ;
197
219
} ;
198
220
199
-
200
221
/**
201
222
* Get refresh token.
202
223
*/
203
224
204
225
RevokeHandler . prototype . getRefreshToken = function ( token , client ) {
205
-
206
226
return Promise . try ( this . model . getRefreshToken , token )
207
227
. then ( function ( token ) {
208
228
if ( ! token ) {
209
- throw new InvalidRequestError ( 'Invalid request : refresh token is invalid' ) ;
229
+ throw new InvalidTokenError ( 'Invalid token : refresh token is invalid' ) ;
210
230
}
211
231
212
232
if ( ! token . client ) {
@@ -218,31 +238,67 @@ RevokeHandler.prototype.getRefreshToken = function(token, client) {
218
238
}
219
239
220
240
if ( token . client . id !== client . id ) {
221
- throw new InvalidRequestError ( 'Invalid request : refresh token is invalid' ) ;
241
+ throw new InvalidTokenError ( 'Invalid token : refresh token client is invalid' ) ;
222
242
}
223
243
224
244
if ( token . refreshTokenExpiresAt && ! ( token . refreshTokenExpiresAt instanceof Date ) ) {
225
245
throw new ServerError ( 'Server error: `refreshTokenExpiresAt` must be a Date instance' ) ;
226
246
}
227
247
228
248
if ( token . refreshTokenExpiresAt && token . refreshTokenExpiresAt < new Date ( ) ) {
229
- throw new InvalidRequestError ( 'Invalid request : refresh token has expired' ) ;
249
+ throw new InvalidTokenError ( 'Invalid token : refresh token has expired' ) ;
230
250
}
231
251
232
252
return token ;
233
253
} ) ;
234
254
} ;
235
255
236
256
/**
237
- * Revoke the refresh token.
257
+ * Get the access token from the model.
258
+ */
259
+
260
+ RevokeHandler . prototype . getAccessToken = function ( token , client ) {
261
+ return Promise . try ( this . model . getAccessToken , token )
262
+ . then ( function ( accessToken ) {
263
+ if ( ! accessToken ) {
264
+ throw new InvalidTokenError ( 'Invalid token: access token is invalid' ) ;
265
+ }
266
+
267
+ if ( ! accessToken . client ) {
268
+ throw new ServerError ( 'Server error: `getAccessToken()` did not return a `client` object' ) ;
269
+ }
270
+
271
+ if ( ! accessToken . user ) {
272
+ throw new ServerError ( 'Server error: `getAccessToken()` did not return a `user` object' ) ;
273
+ }
274
+
275
+ if ( accessToken . client . id !== client . id ) {
276
+ throw new InvalidTokenError ( 'Invalid token: access token is invalid' ) ;
277
+ }
278
+
279
+ if ( accessToken . accessTokenExpiresAt && ! ( accessToken . accessTokenExpiresAt instanceof Date ) ) {
280
+ throw new ServerError ( 'Server error: `expires` must be a Date instance' ) ;
281
+ }
282
+
283
+ if ( accessToken . accessTokenExpiresAt && accessToken . accessTokenExpiresAt < new Date ( ) ) {
284
+ throw new InvalidTokenError ( 'Invalid token: access token has expired.' ) ;
285
+ }
286
+
287
+ return accessToken ;
288
+ } ) ;
289
+ } ;
290
+
291
+ /**
292
+ * Revoke the token.
238
293
*
294
+ * @see https://tools.ietf.org/html/rfc6749#section-6
239
295
*/
240
296
241
297
RevokeHandler . prototype . revokeToken = function ( token ) {
242
298
return Promise . try ( this . model . revokeToken , token )
243
- . then ( function ( status ) {
244
- if ( ! status ) {
245
- throw new InvalidRequestError ( 'Invalid request: refresh token is invalid' ) ;
299
+ . then ( function ( token ) {
300
+ if ( ! token ) {
301
+ throw new InvalidTokenError ( 'Invalid token: token is invalid' ) ;
246
302
}
247
303
248
304
return token ;
0 commit comments