diff --git a/.changeset/famous-cities-stand.md b/.changeset/famous-cities-stand.md new file mode 100644 index 0000000000..86ba727997 --- /dev/null +++ b/.changeset/famous-cities-stand.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-auth-node': patch +--- + +Added the `identity` property to `BackstageSignInResult`. + +The `prepareBackstageIdentityResponse` function will now also forward the `identity` to the response if present in the provided sign-in result. diff --git a/plugins/auth-node/report.api.md b/plugins/auth-node/report.api.md index f693683920..ad0d85030c 100644 --- a/plugins/auth-node/report.api.md +++ b/plugins/auth-node/report.api.md @@ -104,9 +104,7 @@ export type AuthResolverCatalogUserQuery = // @public export type AuthResolverContext = { - issueToken(params: TokenParams): Promise<{ - token: string; - }>; + issueToken(params: TokenParams): Promise; findCatalogUser(query: AuthResolverCatalogUserQuery): Promise<{ entity: Entity; }>; @@ -126,6 +124,7 @@ export interface BackstageIdentityResponse extends BackstageSignInResult { // @public export interface BackstageSignInResult { + identity?: BackstageUserIdentity; token: string; } diff --git a/plugins/auth-node/src/identity/prepareBackstageIdentityResponse.test.ts b/plugins/auth-node/src/identity/prepareBackstageIdentityResponse.test.ts index d37224a11d..5d6527eaa1 100644 --- a/plugins/auth-node/src/identity/prepareBackstageIdentityResponse.test.ts +++ b/plugins/auth-node/src/identity/prepareBackstageIdentityResponse.test.ts @@ -44,6 +44,30 @@ describe('prepareBackstageIdentityResponse', () => { }); }); + it('uses the identity in the result if present', () => { + jest.spyOn(Date, 'now').mockReturnValue(5000); + + const token = mkToken({ sub: 'k:ns/n', ent: ['k:ns/o'], exp: 1005 }); + expect( + prepareBackstageIdentityResponse({ + token, + identity: { + type: 'user', + userEntityRef: 'k:ns/other', + ownershipEntityRefs: ['k:ns/group1', 'k:ns/group2'], + }, + }), + ).toEqual({ + token, + expiresInSeconds: 1000, + identity: { + type: 'user', + userEntityRef: 'k:ns/other', + ownershipEntityRefs: ['k:ns/group1', 'k:ns/group2'], + }, + }); + }); + it('should reject tokens without subject', () => { const token = mkToken({}); expect(() => diff --git a/plugins/auth-node/src/identity/prepareBackstageIdentityResponse.ts b/plugins/auth-node/src/identity/prepareBackstageIdentityResponse.ts index 33e9bafd0d..a1de4e365c 100644 --- a/plugins/auth-node/src/identity/prepareBackstageIdentityResponse.ts +++ b/plugins/auth-node/src/identity/prepareBackstageIdentityResponse.ts @@ -57,7 +57,7 @@ export function prepareBackstageIdentityResponse( return { ...result, expiresInSeconds: exp, - identity: { + identity: result.identity ?? { type: 'user', userEntityRef: sub, ownershipEntityRefs: ent, diff --git a/plugins/auth-node/src/types.ts b/plugins/auth-node/src/types.ts index abcc6a2185..a7202d7748 100644 --- a/plugins/auth-node/src/types.ts +++ b/plugins/auth-node/src/types.ts @@ -34,6 +34,12 @@ export interface BackstageSignInResult { * The token used to authenticate the user within Backstage. */ token: string; + + /** + * Identity information to pass to the client rather than using the + * information that's embeeded in the token. + */ + identity?: BackstageUserIdentity; } /** @@ -141,7 +147,7 @@ export type AuthResolverContext = { /** * Issues a Backstage token using the provided parameters. */ - issueToken(params: TokenParams): Promise<{ token: string }>; + issueToken(params: TokenParams): Promise; /** * Finds a single user in the catalog using the provided query.