From de6c99b043288f9acae6861207f4884c88838d1e Mon Sep 17 00:00:00 2001 From: Alex Crome Date: Tue, 6 Sep 2022 09:35:41 +0100 Subject: [PATCH] Fix access token cache time Signed-off-by: Alex Crome --- ...eInstanceGithubCredentialsProvider.test.ts | 34 ++++++++++++++++++- ...SingleInstanceGithubCredentialsProvider.ts | 7 ++-- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/packages/integration/src/github/SingleInstanceGithubCredentialsProvider.test.ts b/packages/integration/src/github/SingleInstanceGithubCredentialsProvider.test.ts index b48103eea1..d9b2a4e749 100644 --- a/packages/integration/src/github/SingleInstanceGithubCredentialsProvider.test.ts +++ b/packages/integration/src/github/SingleInstanceGithubCredentialsProvider.test.ts @@ -420,7 +420,7 @@ describe('SingleInstanceGithubCredentialsProvider tests', () => { octokit.apps.createInstallationAccessToken.mockReturnValue({ data: { - expires_at: DateTime.local().plus({ hours: 1 }).toString(), + expires_at: DateTime.local().plus({ minutes: 11 }).toString(), token: 'secret_token', }, } as RestEndpointMethodTypes['apps']['createInstallationAccessToken']['response']); @@ -433,4 +433,36 @@ describe('SingleInstanceGithubCredentialsProvider tests', () => { 1, ); }); + + it('should expire access token cache 10 mins before token expires', async () => { + octokit.apps.listInstallations.mockReturnValue({ + headers: { + etag: '123', + }, + data: [ + { + id: 1, + repository_selection: 'all', + account: { + login: 'backstage', + }, + }, + ], + } as RestEndpointMethodTypes['apps']['listInstallations']['response']); + + octokit.apps.createInstallationAccessToken.mockReturnValue({ + data: { + expires_at: DateTime.local().plus({ minutes: 10 }).toString(), + token: 'secret_token', + }, + } as RestEndpointMethodTypes['apps']['createInstallationAccessToken']['response']); + + await github.getCredentials({ url: 'https://github.com/backstage' }); + await github.getCredentials({ url: 'https://github.com/backstage' }); + + expect(octokit.apps.listInstallations.mock.calls.length).toBe(2); + expect(octokit.apps.createInstallationAccessToken.mock.calls.length).toBe( + 2, + ); + }); }); diff --git a/packages/integration/src/github/SingleInstanceGithubCredentialsProvider.ts b/packages/integration/src/github/SingleInstanceGithubCredentialsProvider.ts index a502590a17..02e0893d8a 100644 --- a/packages/integration/src/github/SingleInstanceGithubCredentialsProvider.ts +++ b/packages/integration/src/github/SingleInstanceGithubCredentialsProvider.ts @@ -46,8 +46,10 @@ class Cache { ): Promise<{ accessToken: string }> { let ownerData = this.tokenCache.get(owner); - if (!ownerData || !this.isNotExpired(ownerData.expiresAt)) { + if (!ownerData || this.isExpired(ownerData.expiresAt)) { ownerData = await supplier(); + // Allow 10 minutes grace to account for clock skew + ownerData.expiresAt = ownerData.expiresAt.minus({ minutes: 10 }); this.tokenCache.set(owner, ownerData); } @@ -61,8 +63,7 @@ class Cache { } // consider timestamps older than 50 minutes to be expired. - private isNotExpired = (date: DateTime) => - date.diff(DateTime.local(), 'minutes').minutes > 50; + private isExpired = (date: DateTime) => DateTime.local() > date; private appliesToRepo(tokenData: InstallationTokenData, repo?: string) { // If no specific repo has been requested the token is applicable