diff --git a/.changeset/afraid-trainers-know.md b/.changeset/afraid-trainers-know.md new file mode 100644 index 0000000000..5df3d3eced --- /dev/null +++ b/.changeset/afraid-trainers-know.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend': patch +--- + +Fix a bug preventing an access token to be refreshed a second time with the GitLab provider. diff --git a/plugins/auth-backend/src/providers/gitlab/provider.test.ts b/plugins/auth-backend/src/providers/gitlab/provider.test.ts index f8795aec34..d1a84b43e8 100644 --- a/plugins/auth-backend/src/providers/gitlab/provider.test.ts +++ b/plugins/auth-backend/src/providers/gitlab/provider.test.ts @@ -16,6 +16,7 @@ import { GitlabAuthProvider, gitlabDefaultSignInResolver } from './provider'; import * as helpers from '../../lib/passport/PassportStrategyHelper'; +import { PassportProfile } from '../../lib/passport/types'; import { OAuthResult } from '../../lib/oauth'; import { getVoidLogger } from '@backstage/backend-common'; import { TokenIssuer } from '../../identity'; @@ -27,6 +28,33 @@ const mockFrameHandler = jest.spyOn( ) as unknown as jest.MockedFunction<() => Promise<{ result: OAuthResult }>>; describe('GitlabAuthProvider', () => { + const tokenIssuer = { + issueToken: jest.fn(), + listPublicKeys: jest.fn(), + }; + const catalogIdentityClient = { + findUser: jest.fn(), + }; + + const provider = new GitlabAuthProvider({ + clientId: 'mock', + clientSecret: 'mock', + callbackUrl: 'mock', + baseUrl: 'mock', + catalogIdentityClient: + catalogIdentityClient as unknown as CatalogIdentityClient, + tokenIssuer: tokenIssuer as unknown as TokenIssuer, + authHandler: async ({ fullProfile }) => ({ + profile: { + email: fullProfile.emails![0]!.value, + displayName: fullProfile.displayName, + picture: 'http://gitlab.com/lols', + }, + }), + signInResolver: gitlabDefaultSignInResolver, + logger: getVoidLogger(), + }); + it('should transform to type OAuthResponse', async () => { const tests = [ { @@ -117,36 +145,62 @@ describe('GitlabAuthProvider', () => { }, ]; - const tokenIssuer = { - issueToken: jest.fn(), - listPublicKeys: jest.fn(), - }; - const catalogIdentityClient = { - findUser: jest.fn(), - }; - - const provider = new GitlabAuthProvider({ - clientId: 'mock', - clientSecret: 'mock', - callbackUrl: 'mock', - baseUrl: 'mock', - catalogIdentityClient: - catalogIdentityClient as unknown as CatalogIdentityClient, - tokenIssuer: tokenIssuer as unknown as TokenIssuer, - authHandler: async ({ fullProfile }) => ({ - profile: { - email: fullProfile.emails![0]!.value, - displayName: fullProfile.displayName, - picture: 'http://gitlab.com/lols', - }, - }), - signInResolver: gitlabDefaultSignInResolver, - logger: getVoidLogger(), - }); for (const test of tests) { mockFrameHandler.mockResolvedValueOnce(test.input); const { response } = await provider.handler({} as any); expect(response).toEqual(test.expect); } }); + + it('should forward a new refresh token on refresh', async () => { + const mockRefreshToken = jest.spyOn( + helpers, + 'executeRefreshTokenStrategy', + ) as unknown as jest.MockedFunction<() => Promise<{}>>; + + mockRefreshToken.mockResolvedValueOnce({ + accessToken: 'a.b.c', + refreshToken: 'dont-forget-to-send-refresh', + params: { + id_token: 'my-id', + scope: 'read_user', + }, + }); + + const mockUserProfile = jest.spyOn( + helpers, + 'executeFetchUserProfileStrategy', + ) as unknown as jest.MockedFunction<() => Promise>; + + mockUserProfile.mockResolvedValueOnce({ + id: 'uid-my-id', + username: 'mockuser', + provider: 'gitlab', + displayName: 'Mocked User', + emails: [ + { + value: 'mockuser@gmail.com', + }, + ], + }); + + const response = await provider.refresh({} as any); + + expect(response).toEqual({ + backstageIdentity: { + id: 'mockuser', + }, + profile: { + displayName: 'Mocked User', + email: 'mockuser@gmail.com', + picture: 'http://gitlab.com/lols', + }, + providerInfo: { + accessToken: 'a.b.c', + idToken: 'my-id', + refreshToken: 'dont-forget-to-send-refresh', + scope: 'read_user', + }, + }); + }); }); diff --git a/plugins/auth-backend/src/providers/gitlab/provider.ts b/plugins/auth-backend/src/providers/gitlab/provider.ts index 419f00a346..6ca405d15f 100644 --- a/plugins/auth-backend/src/providers/gitlab/provider.ts +++ b/plugins/auth-backend/src/providers/gitlab/provider.ts @@ -177,6 +177,7 @@ export class GitlabAuthProvider implements OAuthHandlers { providerInfo: { idToken: result.params.id_token, accessToken: result.accessToken, + refreshToken: result.refreshToken, // GitLab expires the old refresh token when used scope: result.params.scope, expiresInSeconds: result.params.expires_in, },