66
77var InvalidArgumentError = require ( '../errors/invalid-argument-error' ) ;
88var InvalidClientError = require ( '../errors/invalid-client-error' ) ;
9+ var InvalidTokenError = require ( '../errors/invalid-token-error' ) ;
910var InvalidRequestError = require ( '../errors/invalid-request-error' ) ;
1011var OAuthError = require ( '../errors/oauth-error' ) ;
1112var Promise = require ( 'bluebird' ) ;
@@ -34,6 +35,10 @@ function RevokeHandler(options) {
3435 throw new InvalidArgumentError ( 'Invalid argument: model does not implement `getRefreshToken()`' ) ;
3536 }
3637
38+ if ( ! options . model . getAccessToken ) {
39+ throw new InvalidArgumentError ( 'Invalid argument: model does not implement `getAccessToken()`' ) ;
40+ }
41+
3742 if ( ! options . model . revokeToken ) {
3843 throw new InvalidArgumentError ( 'Invalid argument: model does not implement `revokeToken()`' ) ;
3944 }
@@ -66,40 +71,57 @@ RevokeHandler.prototype.handle = function(request, response) {
6671 . then ( function ( ) {
6772 return this . getClient ( request , response ) ;
6873 } )
69- . then ( function ( client ) {
74+ . then ( function ( client ) {
7075 return this . handleRevokeToken ( request , client ) ;
7176 } )
72- . then ( function ( ) {
77+ . catch ( function ( e ) {
78+ if ( ! ( e instanceof OAuthError ) ) {
79+ e = new ServerError ( e ) ;
80+ }
7381 /**
7482 * All necessary information is conveyed in the response code.
7583 *
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
7789 */
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 ) ;
8392 }
8493
85- this . updateErrorResponse ( response , e ) ;
86-
8794 throw e ;
8895 } ) ;
8996} ;
9097
9198/**
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"
93104 */
94105
95106RevokeHandler . prototype . handleRevokeToken = function ( request , client ) {
96107 return Promise . bind ( this )
97108 . then ( function ( ) {
98109 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+ } ) ;
103125 } ) ;
104126} ;
105127
@@ -196,17 +218,15 @@ RevokeHandler.prototype.getTokenFromRequest = function(request) {
196218 return bodyToken ;
197219} ;
198220
199-
200221/**
201222 * Get refresh token.
202223 */
203224
204225RevokeHandler . prototype . getRefreshToken = function ( token , client ) {
205-
206226 return Promise . try ( this . model . getRefreshToken , token )
207227 . then ( function ( token ) {
208228 if ( ! token ) {
209- throw new InvalidRequestError ( 'Invalid request : refresh token is invalid' ) ;
229+ throw new InvalidTokenError ( 'Invalid token : refresh token is invalid' ) ;
210230 }
211231
212232 if ( ! token . client ) {
@@ -218,31 +238,67 @@ RevokeHandler.prototype.getRefreshToken = function(token, client) {
218238 }
219239
220240 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' ) ;
222242 }
223243
224244 if ( token . refreshTokenExpiresAt && ! ( token . refreshTokenExpiresAt instanceof Date ) ) {
225245 throw new ServerError ( 'Server error: `refreshTokenExpiresAt` must be a Date instance' ) ;
226246 }
227247
228248 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' ) ;
230250 }
231251
232252 return token ;
233253 } ) ;
234254} ;
235255
236256/**
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.
238293 *
294+ * @see https://tools.ietf.org/html/rfc6749#section-6
239295 */
240296
241297RevokeHandler . prototype . revokeToken = function ( token ) {
242298 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' ) ;
246302 }
247303
248304 return token ;
0 commit comments