feat(client): support custom claims in PrivateKeyJwtProvider (#1875)
This commit is contained in:
parent
6bec24a14c
commit
9ed62fe7d8
2 changed files with 55 additions and 1 deletions
|
|
@ -233,6 +233,16 @@ export interface PrivateKeyJwtProviderOptions {
|
|||
* Space-separated scopes values requested by the client.
|
||||
*/
|
||||
scope?: string;
|
||||
|
||||
/**
|
||||
* Optional custom claims to include in the JWT assertion.
|
||||
* These are merged with the standard claims (`iss`, `sub`, `aud`, `exp`, `iat`, `jti`),
|
||||
* with custom claims taking precedence for any overlapping keys.
|
||||
*
|
||||
* Useful for including additional claims that help scope the access token
|
||||
* with finer granularity than what scopes alone allow.
|
||||
*/
|
||||
claims?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -277,7 +287,8 @@ export class PrivateKeyJwtProvider implements OAuthClientProvider {
|
|||
subject: options.clientId,
|
||||
privateKey: options.privateKey,
|
||||
alg: options.algorithm,
|
||||
lifetimeSeconds: options.jwtLifetimeSeconds
|
||||
lifetimeSeconds: options.jwtLifetimeSeconds,
|
||||
claims: options.claims
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -424,6 +424,49 @@ describe('createPrivateKeyJwtAuth', () => {
|
|||
/Key for the RS256 algorithm must be one of type CryptoKey, KeyObject, or JSON Web Key/
|
||||
);
|
||||
});
|
||||
|
||||
it('includes custom claims in the signed JWT assertion', async () => {
|
||||
const addClientAuth = createPrivateKeyJwtAuth({
|
||||
issuer: 'client-id',
|
||||
subject: 'client-id',
|
||||
privateKey: 'a-string-secret-at-least-256-bits-long',
|
||||
alg: 'HS256',
|
||||
claims: { tenant_id: 'org-123', role: 'admin' }
|
||||
});
|
||||
|
||||
const params = new URLSearchParams();
|
||||
await addClientAuth(new Headers(), params, 'https://auth.example.com/token', undefined);
|
||||
|
||||
const assertion = params.get('client_assertion');
|
||||
expect(assertion).toBeTruthy();
|
||||
|
||||
const jose = await import('jose');
|
||||
const decoded = jose.decodeJwt(assertion!);
|
||||
expect(decoded.tenant_id).toBe('org-123');
|
||||
expect(decoded.role).toBe('admin');
|
||||
expect(decoded.iss).toBe('client-id');
|
||||
expect(decoded.sub).toBe('client-id');
|
||||
});
|
||||
|
||||
it('passes custom claims through PrivateKeyJwtProvider', async () => {
|
||||
const provider = new PrivateKeyJwtProvider({
|
||||
clientId: 'client-id',
|
||||
privateKey: 'a-string-secret-at-least-256-bits-long',
|
||||
algorithm: 'HS256',
|
||||
claims: { tenant_id: 'org-456' }
|
||||
});
|
||||
|
||||
const params = new URLSearchParams();
|
||||
await provider.addClientAuthentication(new Headers(), params, 'https://auth.example.com/token', undefined);
|
||||
|
||||
const assertion = params.get('client_assertion');
|
||||
expect(assertion).toBeTruthy();
|
||||
|
||||
const jose = await import('jose');
|
||||
const decoded = jose.decodeJwt(assertion!);
|
||||
expect(decoded.tenant_id).toBe('org-456');
|
||||
expect(decoded.iss).toBe('client-id');
|
||||
});
|
||||
});
|
||||
|
||||
describe('CrossAppAccessProvider', () => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue