refactor: make token types internal

Co-authored-by: Patrik Oldsberg <poldsberg@gmail.com>
Signed-off-by: Camila Belo <camilaibs@gmail.com>
This commit is contained in:
Camila Belo
2024-04-03 13:35:56 +02:00
parent 22c0bd2adf
commit ff681360cc
6 changed files with 109 additions and 140 deletions
@@ -24,11 +24,7 @@ import {
} from 'jose';
import { MemoryKeyStore } from './MemoryKeyStore';
import { TokenFactory } from './TokenFactory';
import {
BackstageUserIdentityProofPayload,
BackstageTokenPayload,
TokenTypes,
} from '@backstage/plugin-auth-node';
import { tokenTypes } from '@backstage/plugin-auth-node';
const logger = getVoidLogger();
@@ -69,14 +65,11 @@ describe('TokenFactory', () => {
const { keys } = await factory.listPublicKeys();
const keyStore = createLocalJWKSet({ keys: keys });
const verifyResult = await jwtVerify<BackstageTokenPayload>(
token,
keyStore,
);
const verifyResult = await jwtVerify(token, keyStore);
expect(verifyResult.protectedHeader.typ).toBe(tokenTypes.user.typParam);
expect(verifyResult.payload).toEqual({
typ: TokenTypes.user.typClaim,
iss: 'my-issuer',
aud: TokenTypes.user.audClaim,
aud: tokenTypes.user.audClaim,
sub: entityRef,
ent: [entityRef],
'x-fancy-claim': 'my special claim',
@@ -92,14 +85,15 @@ describe('TokenFactory', () => {
const limitedUserToken = [
base64url.encode(
JSON.stringify({
typ: tokenTypes.limitedUser.typParam,
alg: verifyResult.protectedHeader.alg,
kid: verifyResult.protectedHeader.kid!,
}),
),
base64url.encode(
JSON.stringify({
typ: TokenTypes.limitedUser.typClaim,
sub: verifyResult.payload.sub,
ent: verifyResult.payload.ent,
iat: verifyResult.payload.iat,
exp: verifyResult.payload.exp,
}),
@@ -107,14 +101,13 @@ describe('TokenFactory', () => {
verifyResult.payload.uip,
].join('.');
const verifyProofResult =
await jwtVerify<BackstageUserIdentityProofPayload>(
limitedUserToken,
keyStore,
);
const verifyProofResult = await jwtVerify(limitedUserToken, keyStore);
expect(verifyProofResult.protectedHeader.typ).toBe(
tokenTypes.limitedUser.typParam,
);
expect(verifyProofResult.payload).toEqual({
typ: TokenTypes.limitedUser.typClaim,
sub: entityRef,
ent: [entityRef],
iat: expect.any(Number),
exp: expect.any(Number),
});
@@ -28,17 +28,87 @@ import {
import { DateTime } from 'luxon';
import { v4 as uuid } from 'uuid';
import { LoggerService } from '@backstage/backend-plugin-api';
import {
BackstageTokenPayload,
BackstageUserIdentityProofPayload,
TokenParams,
TokenTypes,
} from '@backstage/plugin-auth-node';
import { TokenParams, tokenTypes } from '@backstage/plugin-auth-node';
import { AnyJWK, KeyStore, TokenIssuer } from './types';
import { JsonValue } from '@backstage/types';
const MS_IN_S = 1000;
const MAX_TOKEN_LENGTH = 32768; // At 64 bytes per entity ref this still leaves room for about 500 entities
/**
* The payload contents of a valid Backstage JWT token
*
* @internal
*/
interface BackstageTokenPayload {
/**
* The issuer of the token, currently the discovery URL of the auth backend
*/
iss: string;
/**
* The entity ref of the user
*/
sub: string;
/**
* The entity refs that the user claims ownership througg
*/
ent: string[];
/**
* A hard coded audience string
*/
aud: typeof tokenTypes.user.audClaim;
/**
* Standard expiry in epoch seconds
*/
exp: number;
/**
* Standard issue time in epoch seconds
*/
iat: number;
/**
* A separate user identity proof that the auth service can convert to a limited user token
*/
uip: string;
/**
* Any other custom claims that the adopter may have added
*/
[claim: string]: JsonValue;
}
/**
* The payload contents of a valid Backstage user identity claim token
*
* @internal
*/
interface BackstageUserIdentityProofPayload {
/**
* The entity ref of the user
*/
sub: string;
/**
* The ownership entity refs of the user
*/
ent?: string[];
/**
* Standard expiry in epoch seconds
*/
exp: number;
/**
* Standard issue time in epoch seconds
*/
iat: number;
}
type Options = {
logger: LoggerService;
/** Value of the issuer claim in issued tokens */
@@ -93,7 +163,7 @@ export class TokenFactory implements TokenIssuer {
const iss = this.issuer;
const { sub, ent = [sub], ...additionalClaims } = params.claims;
const aud = TokenTypes.user.audClaim;
const aud = tokenTypes.user.audClaim;
const iat = Math.floor(Date.now() / MS_IN_S);
const exp = iat + this.keyDurationSeconds;
@@ -116,7 +186,7 @@ export class TokenFactory implements TokenIssuer {
const uip = await this.createUserIdentityClaim({
header: {
typ: TokenTypes.limitedUser.typParam,
typ: tokenTypes.limitedUser.typParam,
alg: key.alg,
kid: key.kid,
},
@@ -137,7 +207,7 @@ export class TokenFactory implements TokenIssuer {
const token = await new SignJWT(claims)
.setProtectedHeader({
typ: TokenTypes.user.typParam,
typ: tokenTypes.user.typParam,
alg: key.alg,
kid: key.kid,
})