From 19ac96e4c2987c31af0c97ecbe01cdca5c0288dc Mon Sep 17 00:00:00 2001 From: David Zemon Date: Thu, 8 Sep 2022 11:36:49 -0500 Subject: [PATCH 1/4] feat: Allow passing additional JWT claims to `TokenIssuer` Signed-off-by: David Zemon --- plugins/auth-backend/src/identity/TokenFactory.test.ts | 8 +++++++- plugins/auth-backend/src/identity/TokenFactory.ts | 5 ++--- plugins/auth-backend/src/identity/types.ts | 10 ++++++++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/plugins/auth-backend/src/identity/TokenFactory.test.ts b/plugins/auth-backend/src/identity/TokenFactory.test.ts index 9a163b3ff5..4f6df89210 100644 --- a/plugins/auth-backend/src/identity/TokenFactory.test.ts +++ b/plugins/auth-backend/src/identity/TokenFactory.test.ts @@ -48,7 +48,12 @@ describe('TokenFactory', () => { await expect(factory.listPublicKeys()).resolves.toEqual({ keys: [] }); const token = await factory.issueToken({ - claims: { sub: entityRef, ent: [entityRef] }, + claims: { + sub: entityRef, + ent: [entityRef], + 'x-fancy-claim': 'my special claim', + aud: 'this value will be overridden', + }, }); const { keys } = await factory.listPublicKeys(); @@ -60,6 +65,7 @@ describe('TokenFactory', () => { aud: 'backstage', sub: entityRef, ent: [entityRef], + 'x-fancy-claim': 'my special claim', iat: expect.any(Number), exp: expect.any(Number), }); diff --git a/plugins/auth-backend/src/identity/TokenFactory.ts b/plugins/auth-backend/src/identity/TokenFactory.ts index 44cfebfb71..f80b79b6bc 100644 --- a/plugins/auth-backend/src/identity/TokenFactory.ts +++ b/plugins/auth-backend/src/identity/TokenFactory.ts @@ -77,8 +77,7 @@ export class TokenFactory implements TokenIssuer { const key = await this.getKey(); const iss = this.issuer; - const sub = params.claims.sub; - const ent = params.claims.ent; + const { sub, ent, ...additionalClaims } = params.claims; const aud = 'backstage'; const iat = Math.floor(Date.now() / MS_IN_S); const exp = iat + this.keyDurationSeconds; @@ -98,7 +97,7 @@ export class TokenFactory implements TokenIssuer { throw new AuthenticationError('No algorithm was provided in the key'); } - return new SignJWT({ iss, sub, ent, aud, iat, exp }) + return new SignJWT({ ...additionalClaims, iss, sub, ent, aud, iat, exp }) .setProtectedHeader({ alg: key.alg, kid: key.kid }) .setIssuer(iss) .setAudience(aud) diff --git a/plugins/auth-backend/src/identity/types.ts b/plugins/auth-backend/src/identity/types.ts index 4765b50d7d..49d78b8472 100644 --- a/plugins/auth-backend/src/identity/types.ts +++ b/plugins/auth-backend/src/identity/types.ts @@ -28,13 +28,19 @@ export interface AnyJWK extends Record { * @public */ export type TokenParams = { - /** The claims that will be embedded within the token */ + /** + * The claims that will be embedded within the token. At a minimum, this should include + * the subject claim, `sub`. It is common to also list entity ownership relations in the + * `ent` list. Additional claims may also be added at the developer's discretion except + * for the following list, which will be overwritten by the TokenIssuer: `iss`, `aud`, + * `iat`, and `exp`. + */ claims: { /** The token subject, i.e. User ID */ sub: string; /** A list of entity references that the user claims ownership through */ ent?: string[]; - }; + } & Record; }; /** From 5b011fb2e6aa88964fe737531fe2296e7e3f8dbb Mon Sep 17 00:00:00 2001 From: David Zemon Date: Thu, 8 Sep 2022 11:48:36 -0500 Subject: [PATCH 2/4] chore: Add changeset Signed-off-by: David Zemon --- .changeset/cold-bananas-hang.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/cold-bananas-hang.md diff --git a/.changeset/cold-bananas-hang.md b/.changeset/cold-bananas-hang.md new file mode 100644 index 0000000000..8e535a5532 --- /dev/null +++ b/.changeset/cold-bananas-hang.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend': patch +--- + +Allow adding misc claims to JWT From dba3c15c96be917c99461158a16f6a9dfafab3b0 Mon Sep 17 00:00:00 2001 From: David Zemon Date: Thu, 8 Sep 2022 12:06:23 -0500 Subject: [PATCH 3/4] chore: Add API report Signed-off-by: David Zemon --- plugins/auth-backend/api-report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/auth-backend/api-report.md b/plugins/auth-backend/api-report.md index d47abeee83..2420a79a79 100644 --- a/plugins/auth-backend/api-report.md +++ b/plugins/auth-backend/api-report.md @@ -706,7 +706,7 @@ export type TokenParams = { claims: { sub: string; ent?: string[]; - }; + } & Record; }; // @public (undocumented) From c8e837da5b9427cacb1db5a3b562f11466226699 Mon Sep 17 00:00:00 2001 From: David Zemon Date: Mon, 19 Sep 2022 08:00:18 -0500 Subject: [PATCH 4/4] feat: Use JsonValue for JWT claim values Signed-off-by: David Zemon --- plugins/auth-backend/api-report.md | 2 +- plugins/auth-backend/src/identity/types.ts | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/plugins/auth-backend/api-report.md b/plugins/auth-backend/api-report.md index 2420a79a79..6e9de12cdb 100644 --- a/plugins/auth-backend/api-report.md +++ b/plugins/auth-backend/api-report.md @@ -706,7 +706,7 @@ export type TokenParams = { claims: { sub: string; ent?: string[]; - } & Record; + } & Record; }; // @public (undocumented) diff --git a/plugins/auth-backend/src/identity/types.ts b/plugins/auth-backend/src/identity/types.ts index 49d78b8472..e325f74c81 100644 --- a/plugins/auth-backend/src/identity/types.ts +++ b/plugins/auth-backend/src/identity/types.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { JsonValue } from '@backstage/types'; + /** Represents any form of serializable JWK */ export interface AnyJWK extends Record { use: 'sig'; @@ -33,14 +35,15 @@ export type TokenParams = { * the subject claim, `sub`. It is common to also list entity ownership relations in the * `ent` list. Additional claims may also be added at the developer's discretion except * for the following list, which will be overwritten by the TokenIssuer: `iss`, `aud`, - * `iat`, and `exp`. + * `iat`, and `exp`. The Backstage team also maintains the right add new claims in the future + * without listing the change as a "breaking change". */ claims: { /** The token subject, i.e. User ID */ sub: string; /** A list of entity references that the user claims ownership through */ ent?: string[]; - } & Record; + } & Record; }; /**