diff --git a/.changeset/two-worms-float.md b/.changeset/two-worms-float.md new file mode 100644 index 000000000..0ef2731ed --- /dev/null +++ b/.changeset/two-worms-float.md @@ -0,0 +1,5 @@ +--- +"@web5/credentials": patch +--- + +Replaced hardcoded `typ` value in JWT with an optional header override. diff --git a/packages/credentials/src/jwt.ts b/packages/credentials/src/jwt.ts index 125866196..37d9b6786 100644 --- a/packages/credentials/src/jwt.ts +++ b/packages/credentials/src/jwt.ts @@ -66,6 +66,12 @@ export type SignJwtOptions = { signerDid: BearerDid /** The payload to sign. */ payload: JwtPayload + + /** Overridable header parameters */ + header?: { + /** Type Header Parameter */ + typ: string + } } /** @@ -108,9 +114,9 @@ export class Jwt { } const header: JwtHeaderParams = { - typ : 'JWT', alg : signer.algorithm, kid : vmId, + ...options.header, }; const base64UrlEncodedHeader = Convert.object(header).toBase64Url(); @@ -210,10 +216,6 @@ export class Jwt { throw new Error('Verification failed: Malformed JWT. Invalid base64url encoding for JWT header'); } - if (!jwtHeader.typ || jwtHeader.typ !== 'JWT') { - throw new Error('Verification failed: Expected JWT header to contain typ property set to JWT'); - } - if (!jwtHeader.alg || !jwtHeader.kid) { // ensure that JWT header has required properties throw new Error('Verification failed: Expected JWT header to contain alg and kid'); } diff --git a/packages/credentials/tests/jwt.spec.ts b/packages/credentials/tests/jwt.spec.ts index 58f418eef..8e718a0e2 100644 --- a/packages/credentials/tests/jwt.spec.ts +++ b/packages/credentials/tests/jwt.spec.ts @@ -25,24 +25,6 @@ describe('Jwt', () => { ).to.throw('Invalid base64url encoding for JWT header'); }); - it('throws error if JWT header is missing typ property', async () => { - const header: JwtHeaderParams = { alg: 'ES256K', kid: 'whateva' }; - const base64UrlEncodedHeader = Convert.object(header).toBase64Url(); - - expect(() => - Jwt.parse({ jwt: `${base64UrlEncodedHeader}.efgh.hijk` }) - ).to.throw('typ property set to JWT'); - }); - - it('throws error if JWT header typ property is not set to JWT', async () => { - const header: JwtHeaderParams = { typ: 'hehe', alg: 'ES256K', kid: 'whateva' }; - const base64UrlEncodedHeader = Convert.object(header).toBase64Url(); - - expect(() => - Jwt.parse({ jwt: `${base64UrlEncodedHeader}.efgh.hijk` }) - ).to.throw('typ property set to JWT'); - }); - it('throws error if JWT header alg property is missing', async () => { // @ts-expect-error because alg is intentionally missing to trigger error. const header: JwtHeaderParams = { typ: 'JWT', kid: 'whateva' }; @@ -274,6 +256,20 @@ describe('Jwt', () => { }); }); + describe('sign()', () => { + it('allows typ to be set by caller', async () => { + const did = await DidJwk.create(); + const signedJwt = await Jwt.sign({ + signerDid : did, + payload : {jti: 'hehe'}, + header : {typ: 'openid4vci-proof+jwt'} + }); + + const parsed = Jwt.parse({ jwt: signedJwt }); + expect(parsed.decoded.header.typ).to.equal('openid4vci-proof+jwt'); + }); + }); + describe('Web5TestVectorsVcJwt', () => { it('decode', async () => { const vectors = JwtDecodeTestVector.vectors;