diff --git a/.changeset/pretty-insects-yell.md b/.changeset/pretty-insects-yell.md new file mode 100644 index 0000000000..6c3c5bb165 --- /dev/null +++ b/.changeset/pretty-insects-yell.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend-module-oidc-provider': patch +--- + +Support revoke refresh token to oidc logout function diff --git a/plugins/auth-backend-module-oidc-provider/src/authenticator.test.ts b/plugins/auth-backend-module-oidc-provider/src/authenticator.test.ts index 717083562c..eb6389f48b 100644 --- a/plugins/auth-backend-module-oidc-provider/src/authenticator.test.ts +++ b/plugins/auth-backend-module-oidc-provider/src/authenticator.test.ts @@ -34,6 +34,7 @@ describe('oidcAuthenticator', () => { let oauthState: OAuthState; let idToken: string; let publicKey: JWK; + const revokedTokenMap: Record = {}; const mswServer = setupServer(); setupRequestMockHandlers(mswServer); @@ -96,6 +97,13 @@ describe('oidcAuthenticator', () => { res(ctx.status(200), ctx.json({ keys: [{ ...publicKey }] })), ), rest.post('https://oidc.test/oauth2/token', async (req, res, ctx) => { + const formBody = new URLSearchParams(await req.text()); + if ( + formBody.get('grant_type') === 'refresh_token' && + revokedTokenMap[formBody.get('refresh_token') as string] + ) { + return res(ctx.json({})); + } return res( req.headers.get('Authorization') ? ctx.json({ @@ -123,6 +131,14 @@ describe('oidcAuthenticator', () => { }), ), ), + rest.post( + 'https://oidc.test/oauth2/revoke_token', + async (req, res, ctx) => { + const formBody = new URLSearchParams(await req.text()); + revokedTokenMap[formBody.get('token') as string] = true; + return res(ctx.status(200)); + }, + ), ); implementation = oidcAuthenticator.initialize({ @@ -434,4 +450,30 @@ describe('oidcAuthenticator', () => { expect(refreshResponse.session.idToken).toBe(idToken); }); }); + + describe('#logout', () => { + it('should revoke refreshToken', async () => { + const refreshToken = 'revokeRefreshToken'; + const refreshRequest = { + scope: '', + refreshToken, + req: {} as express.Request, + }; + const logoutRequest = { + refreshToken, + req: {} as express.Request, + }; + + await oidcAuthenticator.logout?.(logoutRequest, implementation); + + const refreshResponse = oidcAuthenticator.refresh( + refreshRequest, + implementation, + ); + + await expect(refreshResponse).rejects.toEqual( + new Error('Refresh failed'), + ); + }); + }); }); diff --git a/plugins/auth-backend-module-oidc-provider/src/authenticator.ts b/plugins/auth-backend-module-oidc-provider/src/authenticator.ts index c3754b6f19..317cb7269e 100644 --- a/plugins/auth-backend-module-oidc-provider/src/authenticator.ts +++ b/plugins/auth-backend-module-oidc-provider/src/authenticator.ts @@ -197,4 +197,12 @@ export const oidcAuthenticator = createOAuthAuthenticator({ }); }); }, + + async logout(input, ctx) { + const { client } = await ctx.promise; + + if (input.refreshToken) { + await client.revoke(input.refreshToken); + } + }, });