import { createPrivateKey, generateKeyPairSync } from 'node:crypto'; import { buildBffSigningKey } from './bff-signing-key'; function rsaKey() { const { privateKey } = generateKeyPairSync('rsa', { modulusLength: 2048 }); return createPrivateKey(privateKey.export({ type: 'pkcs8', format: 'pem' })); } function ecKey(curve: 'prime256v1' | 'secp384r1') { const { privateKey } = generateKeyPairSync('ec', { namedCurve: curve }); return createPrivateKey(privateKey.export({ type: 'pkcs8', format: 'pem' })); } describe('buildBffSigningKey', () => { it('produces a public JWK with kid + alg + use=sig from an RSA private key', async () => { const key = await buildBffSigningKey({ privateKey: rsaKey(), kid: 'bff-2026-05', alg: 'RS256', }); expect(key.publicJwk.kty).toBe('RSA'); expect(key.publicJwk.kid).toBe('bff-2026-05'); expect(key.publicJwk.alg).toBe('RS256'); expect(key.publicJwk.use).toBe('sig'); // No private-material leak — the public JWK must not carry `d`, `p`, `q`, `dp`, `dq`, `qi`. expect(key.publicJwk.d).toBeUndefined(); expect(key.publicJwk.p).toBeUndefined(); expect(key.publicJwk.q).toBeUndefined(); }); it('produces a public JWK with kty=EC + crv=P-256 for an EC P-256 key', async () => { const key = await buildBffSigningKey({ privateKey: ecKey('prime256v1'), kid: 'bff-2026-05', alg: 'ES256', }); expect(key.publicJwk.kty).toBe('EC'); expect(key.publicJwk.crv).toBe('P-256'); expect(key.publicJwk.alg).toBe('ES256'); expect(key.publicJwk.d).toBeUndefined(); }); it('produces a public JWK with crv=P-384 for an EC P-384 key', async () => { const key = await buildBffSigningKey({ privateKey: ecKey('secp384r1'), kid: 'bff-2026-05', alg: 'ES384', }); expect(key.publicJwk.crv).toBe('P-384'); expect(key.publicJwk.alg).toBe('ES384'); }); it('exposes the full original config on the returned BffSigningKey', async () => { const privateKey = rsaKey(); const built = await buildBffSigningKey({ privateKey, kid: 'rotated-kid', alg: 'RS256' }); expect(built.config.privateKey).toBe(privateKey); expect(built.config.kid).toBe('rotated-kid'); expect(built.config.alg).toBe('RS256'); }); });