diff --git a/api/auth/index.ts b/api/auth/index.ts index 4f39e5a..67e95a9 100644 --- a/api/auth/index.ts +++ b/api/auth/index.ts @@ -41,20 +41,30 @@ export class SmartlingAuthApi extends SmartlingBaseApi implements AccessTokenPro this.logger.debug(`Refresh token with: ${JSON.stringify(this.response, SmartlingBaseApi.sensitiveReplacer)}`); - return await this.makeRequest( + const refreshedToken: AccessTokenDto = await this.makeRequest( "post", `${this.entrypoint}/authenticate/refresh`, JSON.stringify({ refreshToken: this.response.refreshToken }) ); + + if (!this.isSessionCapped(refreshedToken)) { + return refreshedToken; + } + + this.logger.debug(`Refreshed token has a session-capped lifetime (${refreshedToken.refreshExpiresIn}s); re-authenticating.`); } - this.logger.debug(`Can't refresh, doing re-auth with: ${JSON.stringify(this.response, SmartlingBaseApi.sensitiveReplacer)}`); + this.logger.debug(`Falling back to re-auth with: ${JSON.stringify(this.response, SmartlingBaseApi.sensitiveReplacer)}`); return await this.authenticate(); } + isSessionCapped(response: AccessTokenDto): boolean { + return response.refreshExpiresIn > 0 && response.refreshExpiresIn < this.ttlCorrectionSec; + } + resetRequestTimeStamp(): void { this.requestTimestamp = this.time(); } diff --git a/package-lock.json b/package-lock.json index 40882f9..3c9e5bf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "smartling-api-sdk-nodejs", - "version": "2.34.0", + "version": "2.35.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "smartling-api-sdk-nodejs", - "version": "2.34.0", + "version": "2.35.1", "license": "ISC", "dependencies": { "@types/mocha": "^9.0.0", diff --git a/package.json b/package.json index f6a7608..a623331 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "smartling-api-sdk-nodejs", - "version": "2.35.0", + "version": "2.35.1", "description": "Package for Smartling API", "main": "built/index.js", "engines": { diff --git a/test/auth.spec.ts b/test/auth.spec.ts index cc5122a..18aa1a3 100644 --- a/test/auth.spec.ts +++ b/test/auth.spec.ts @@ -72,6 +72,7 @@ describe("Auth class tests.", () => { authTokenExistsStub.returns(true); authTokenCanBeRenewedStub.returns(true); auth.response = { refreshToken: "test_refresh_token" }; + authMakeRequestStub.returns({ accessToken: "refreshed_token", refreshExpiresIn: 3600 }); await auth.refreshToken(); @@ -90,6 +91,50 @@ describe("Auth class tests.", () => { sinon.assert.notCalled(authAuthenticateStub); }); + it("Token exists, can be renewed, and refresh returns a normal (non-capped) token: refreshed token is returned as-is.", async () => { + authTokenExistsStub.returns(true); + authTokenCanBeRenewedStub.returns(true); + auth.response = { refreshToken: "test_refresh_token" }; + + const refreshedResponse = { accessToken: "refreshed_token", refreshExpiresIn: 3600 }; + authMakeRequestStub.returns(refreshedResponse); + + const result = await auth.refreshToken(); + + sinon.assert.notCalled(authAuthenticateStub); + assert.deepEqual(result, refreshedResponse); + }); + + it("Token exists, can be renewed, but refresh returns a session-capped token: falls through to authenticate.", async () => { + authTokenExistsStub.returns(true); + authTokenCanBeRenewedStub.returns(true); + auth.response = { refreshToken: "test_refresh_token" }; + + const cappedResponse = { accessToken: "capped_refreshed_token", refreshExpiresIn: 5 }; + authMakeRequestStub.returns(cappedResponse); + authAuthenticateStub.returns({ accessToken: "reauthed_token" }); + + const result = await auth.refreshToken(); + + sinon.assert.calledOnce(authMakeRequestStub); + sinon.assert.calledOnce(authAuthenticateStub); + assert.deepEqual(result, { accessToken: "reauthed_token" }); + }); + + it("Token exists, can be renewed, and refresh returns an offline-type token (refreshExpiresIn: 0): treated as non-capped, not re-authenticated.", async () => { + authTokenExistsStub.returns(true); + authTokenCanBeRenewedStub.returns(true); + auth.response = { refreshToken: "test_refresh_token" }; + + const offlineResponse = { accessToken: "offline_refreshed_token", refreshExpiresIn: 0 }; + authMakeRequestStub.returns(offlineResponse); + + const result = await auth.refreshToken(); + + sinon.assert.notCalled(authAuthenticateStub); + assert.deepEqual(result, offlineResponse); + }); + it("Token exists but can't be renewed.", async () => { authTokenExistsStub.returns(true); authTokenCanBeRenewedStub.returns(false);