chore: add changesets, update API reports, fix type errors

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Jonathan Roebuck <jroebuck@spotify.com>
This commit is contained in:
Jonathan Roebuck
2026-03-31 15:15:51 +01:00
parent 906f104f6b
commit 9244b70c57
6 changed files with 27 additions and 4 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-auth-node': minor
---
Added `OAuthAuthenticatorLogoutResult` type. The `logout` method on `OAuthAuthenticator` can now optionally return `{ logoutUrl }` to trigger a browser redirect after sign-out. This allows providers like Auth0 to clear their session cookies by redirecting to their logout endpoint.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-auth-backend-module-auth0-provider': minor
---
Added federated logout support. On sign-out, the Auth0 authenticator now returns a logout URL that redirects the browser to Auth0's `/v2/logout?federated` endpoint, clearing both the Auth0 session and any upstream IdP session. This ensures users must fully re-authenticate after signing out.
@@ -0,0 +1,5 @@
---
'@backstage/core-app-api': patch
---
The `DefaultAuthConnector` now checks for a `logoutUrl` in the logout response body. If the auth provider returns one (e.g. Auth0 federated logout), the browser is redirected to that URL to clear the provider's session cookies. This is backward compatible — providers that return an empty response are unaffected.
+9 -1
View File
@@ -293,7 +293,10 @@ export interface OAuthAuthenticator<TContext, TProfile> {
// (undocumented)
initialize(ctx: { callbackUrl: string; config: Config }): TContext;
// (undocumented)
logout?(input: OAuthAuthenticatorLogoutInput, ctx: TContext): Promise<void>;
logout?(
input: OAuthAuthenticatorLogoutInput,
ctx: TContext,
): Promise<void | OAuthAuthenticatorLogoutResult>;
// (undocumented)
refresh(
input: OAuthAuthenticatorRefreshInput,
@@ -329,6 +332,11 @@ export interface OAuthAuthenticatorLogoutInput {
req: Request_2;
}
// @public (undocumented)
export interface OAuthAuthenticatorLogoutResult {
logoutUrl?: string;
}
// @public (undocumented)
export interface OAuthAuthenticatorRefreshInput {
// (undocumented)
@@ -1265,7 +1265,7 @@ describe('createOAuthRouteHandlers', () => {
});
it('should return logoutUrl as JSON when authenticator provides one', async () => {
mockAuthenticator.logout.mockResolvedValueOnce({
(mockAuthenticator.logout as jest.Mock).mockResolvedValueOnce({
logoutUrl: 'https://example.auth0.com/v2/logout?federated',
});
@@ -1293,7 +1293,7 @@ describe('createOAuthRouteHandlers', () => {
});
it('should return empty body when authenticator logout returns void', async () => {
mockAuthenticator.logout.mockResolvedValueOnce(undefined);
(mockAuthenticator.logout as jest.Mock).mockResolvedValueOnce(undefined);
const agent = request.agent(
wrapInApp(createOAuthRouteHandlers(baseConfig)),
@@ -280,7 +280,7 @@ export function createOAuthRouteHandlers<TProfile>(
throw new AuthenticationError('Invalid X-Requested-With header');
}
let logoutResult: void | { logoutUrl?: string };
let logoutResult: void | { logoutUrl?: string } = undefined;
if (authenticator.logout) {
const refreshToken = cookieManager.getRefreshToken(req);
logoutResult = await authenticator.logout(