From 176ef7b8fd7a898a3e6e9ab77433efc607b36e2f Mon Sep 17 00:00:00 2001 From: Aras Abbasi Date: Sun, 30 Jun 2024 02:01:51 +0200 Subject: [PATCH] Preserve old refresh token if new token does not contain refresh token (#434) --- lib/access-token.js | 3 +++ test/_authorization-server-mock.js | 9 +++++++++ test/access-token-refresh.js | 24 ++++++++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/lib/access-token.js b/lib/access-token.js index e8cbff2..528371d 100644 --- a/lib/access-token.js +++ b/lib/access-token.js @@ -48,6 +48,9 @@ module.exports = class AccessToken { const parameters = GrantTypeParams.forGrantType(REFRESH_TOKEN_PROPERTY_NAME, this.#config.options, refreshParams); const response = await this.#client.request(this.#config.auth.refreshPath, parameters.toObject(), httpOptions); + if (response[REFRESH_TOKEN_PROPERTY_NAME] === undefined) { + response.refresh_token = this.refresh_token; + } return new AccessToken(this.#config, this.#client, response); } diff --git a/test/_authorization-server-mock.js b/test/_authorization-server-mock.js index af96732..697875d 100644 --- a/test/_authorization-server-mock.js +++ b/test/_authorization-server-mock.js @@ -88,6 +88,14 @@ function createAuthorizationServer(authorizationServerUrl) { }); } + function tokenSuccessWithoutRefreshToken(scopeOptions, params) { + return nock(authorizationServerUrl, scopeOptions) + .post('/oauth/token', params) + .reply(200, { ...accessToken, refresh_token: undefined }, { + 'Content-Type': 'application/json', + }); + } + return { tokenError, tokenAuthorizationError, @@ -98,6 +106,7 @@ function createAuthorizationServer(authorizationServerUrl) { tokenSuccessWithNonJSONContent, tokenSuccessWithCustomPath, tokenSuccess, + tokenSuccessWithoutRefreshToken, }; } diff --git a/test/access-token-refresh.js b/test/access-token-refresh.js index 45b0450..bf4f7ef 100644 --- a/test/access-token-refresh.js +++ b/test/access-token-refresh.js @@ -271,3 +271,27 @@ test.serial('@refresh => creates a new access token with custom (inline) http op scope.done(); t.true(has(refreshAccessToken.token, 'access_token')); }); + +test.serial('@refresh => creates a new access token with keeping the old refresh token if refresh did not provide a new refresh token', async (t) => { + const config = createModuleConfig(); + + const accessTokenResponse = chance.accessToken({ + expireMode: 'expires_in', + }); + + const client = new Client(config); + + const refreshParams = { + grant_type: 'refresh_token', + refresh_token: accessTokenResponse.refresh_token, + }; + + const server = createAuthorizationServer('https://authorization-server.org:443'); + const scope = server.tokenSuccessWithoutRefreshToken(scopeOptions, refreshParams); + + const accessToken = new AccessToken(config, client, accessTokenResponse); + const refreshAccessToken = await accessToken.refresh(); + + scope.done(); + t.true(has(refreshAccessToken.token, 'refresh_token')); +});