diff --git a/src/jwt/produce.ts b/src/jwt/produce.ts index 50f58ed084..26a7905239 100644 --- a/src/jwt/produce.ts +++ b/src/jwt/produce.ts @@ -15,8 +15,8 @@ function validateInput(label: string, input: number) { export class ProduceJWT { protected _payload!: JWTPayload - /** @param payload The JWT Claims Set object. */ - constructor(payload: JWTPayload) { + /** @param payload The JWT Claims Set object. Defaults to an empty object. */ + constructor(payload: JWTPayload = {}) { if (!isObject(payload)) { throw new TypeError('JWT Claims Set MUST be an object') } diff --git a/tap/jwks.ts b/tap/jwks.ts index 57f2f0d3c9..ab8c265e40 100644 --- a/tap/jwks.ts +++ b/tap/jwks.ts @@ -105,7 +105,7 @@ export default (QUnit: QUnit, lib: typeof jose) => { { const [jwk] = keys const key = await lib.importJWK({ ...jwk, alg: 'PS256' }) - const jwt = await new lib.SignJWT({}) + const jwt = await new lib.SignJWT() .setProtectedHeader({ alg: 'PS256', kid: jwk.kid }) .sign(key) const { key: resolvedKey } = await lib.jwtVerify(jwt, JWKS) diff --git a/test/jwks/remote.test.mjs b/test/jwks/remote.test.mjs index 2de6542d90..5acffec7d6 100644 --- a/test/jwks/remote.test.mjs +++ b/test/jwks/remote.test.mjs @@ -126,7 +126,7 @@ test.serial('RemoteJWKSet', async (t) => { { const [jwk] = keys const key = await importJWK({ ...jwk, alg: 'PS256' }) - const jwt = await new SignJWT({}).setProtectedHeader({ alg: 'PS256', kid: jwk.kid }).sign(key) + const jwt = await new SignJWT().setProtectedHeader({ alg: 'PS256', kid: jwk.kid }).sign(key) await t.notThrowsAsync(async () => { const { key: resolvedKey } = await jwtVerify(jwt, JWKS) t.truthy(resolvedKey) @@ -178,7 +178,7 @@ test.serial('RemoteJWKSet', async (t) => { { const [jwk] = keys const key = await importJWK({ ...jwk, alg: 'RS256' }) - const jwt = await new SignJWT({}).setProtectedHeader({ alg: 'RS256' }).sign(key) + const jwt = await new SignJWT().setProtectedHeader({ alg: 'RS256' }).sign(key) let error = await t.throwsAsync(jwtVerify(jwt, JWKS), { code: 'ERR_JWKS_MULTIPLE_MATCHING_KEYS', message: 'multiple matching keys found in the JSON Web Key Set', @@ -206,7 +206,7 @@ test.serial('RemoteJWKSet', async (t) => { { const [, jwk] = keys const key = await importJWK({ ...jwk, alg: 'PS256' }) - const jwt = await new SignJWT({}).setProtectedHeader({ alg: 'PS256', kid: jwk.kid }).sign(key) + const jwt = await new SignJWT().setProtectedHeader({ alg: 'PS256', kid: jwk.kid }).sign(key) await t.throwsAsync(jwtVerify(jwt, JWKS), { code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no applicable key found in the JSON Web Key Set', @@ -215,7 +215,7 @@ test.serial('RemoteJWKSet', async (t) => { { const [, , jwk] = keys const key = await importJWK({ ...jwk, alg: 'ES256' }) - const jwt = await new SignJWT({}).setProtectedHeader({ alg: 'ES256' }).sign(key) + const jwt = await new SignJWT().setProtectedHeader({ alg: 'ES256' }).sign(key) await t.notThrowsAsync(jwtVerify(jwt, JWKS)) } }) @@ -247,12 +247,12 @@ test.serial('refreshes the JWKS once off cooldown', async (t) => { const JWKS = createRemoteJWKSet(url) const key = await importJWK({ ...jwk, alg: 'ES256' }) { - const jwt = await new SignJWT({}).setProtectedHeader({ alg: 'ES256', kid: 'one' }).sign(key) + const jwt = await new SignJWT().setProtectedHeader({ alg: 'ES256', kid: 'one' }).sign(key) await t.notThrowsAsync(jwtVerify(jwt, JWKS)) await t.notThrowsAsync(jwtVerify(jwt, JWKS)) } { - const jwt = await new SignJWT({}).setProtectedHeader({ alg: 'ES256', kid: 'two' }).sign(key) + const jwt = await new SignJWT().setProtectedHeader({ alg: 'ES256', kid: 'two' }).sign(key) await t.throwsAsync(jwtVerify(jwt, JWKS), { code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no applicable key found in the JSON Web Key Set', @@ -291,7 +291,7 @@ test.serial('refreshes the JWKS once stale', async (t) => { const JWKS = createRemoteJWKSet(url, { cacheMaxAge: 60 * 10 * 1000 }) const key = await importJWK({ ...jwk, alg: 'ES256' }) { - const jwt = await new SignJWT({}).setProtectedHeader({ alg: 'ES256', kid: 'one' }).sign(key) + const jwt = await new SignJWT().setProtectedHeader({ alg: 'ES256', kid: 'one' }).sign(key) await t.notThrowsAsync(jwtVerify(jwt, JWKS)) await t.notThrowsAsync(jwtVerify(jwt, JWKS)) timekeeper.travel((now + 60 * 10) * 1000) @@ -326,7 +326,7 @@ test.serial('can be configured to never be stale', async (t) => { const JWKS = createRemoteJWKSet(url, { cacheMaxAge: Infinity }) const key = await importJWK({ ...jwk, alg: 'ES256' }) { - const jwt = await new SignJWT({}).setProtectedHeader({ alg: 'ES256', kid: 'one' }).sign(key) + const jwt = await new SignJWT().setProtectedHeader({ alg: 'ES256', kid: 'one' }).sign(key) await t.notThrowsAsync(jwtVerify(jwt, JWKS)) await t.notThrowsAsync(jwtVerify(jwt, JWKS)) timekeeper.travel((now + 60 * 10) * 1000) diff --git a/test/jwt/encrypt.test.mjs b/test/jwt/encrypt.test.mjs index d01e2f66fb..ce1d74d5ee 100644 --- a/test/jwt/encrypt.test.mjs +++ b/test/jwt/encrypt.test.mjs @@ -67,15 +67,8 @@ test('EncryptJWT w/crit', async (t) => { ) }) -test('new EncryptJWT', (t) => { - t.throws(() => new EncryptJWT(), { - instanceOf: TypeError, - message: 'JWT Claims Set MUST be an object', - }) -}) - async function testJWTsetFunction(t, method, claim, value, duplicate = false, expected = value) { - let enc = new EncryptJWT({}).setProtectedHeader({ alg: 'dir', enc: 'A128GCM' })[method](value) + let enc = new EncryptJWT().setProtectedHeader({ alg: 'dir', enc: 'A128GCM' })[method](value) if (duplicate) { enc = enc[`replicate${method.slice(3)}AsHeader`]() diff --git a/test/jwt/sign.test.mjs b/test/jwt/sign.test.mjs index a299c810f5..2e7c472667 100644 --- a/test/jwt/sign.test.mjs +++ b/test/jwt/sign.test.mjs @@ -24,6 +24,11 @@ test('SignJWT', async (t) => { ) }) +test('SignJWT with default (empty) payload', async (t) => { + const jwt = await new SignJWT().setProtectedHeader({ alg: 'HS256' }).sign(t.context.secret) + t.is(jwt, 'eyJhbGciOiJIUzI1NiJ9.e30.4E_Bsx-pJi3kOW9wVXN8CgbATwP09D9V5gxh9-9zSZ0') +}) + test('SignJWT w/crit', async (t) => { const expected = 'eyJhbGciOiJIUzI1NiIsImNyaXQiOlsiaHR0cDovL29wZW5iYW5raW5nLm9yZy51ay9pYXQiXSwiaHR0cDovL29wZW5iYW5raW5nLm9yZy51ay9pYXQiOjB9.eyJ1cm46ZXhhbXBsZTpjbGFpbSI6dHJ1ZX0.YzOrPZaNql7PpCo43HAJdj-LASP8lOmtb-Bzj9OrNAk' @@ -61,29 +66,22 @@ test('SignJWT w/crit', async (t) => { ) }) -test('new SignJWT', (t) => { - t.throws(() => new SignJWT(), { - instanceOf: TypeError, - message: 'JWT Claims Set MUST be an object', - }) -}) - test('Signed JWTs cannot use unencoded payload', async (t) => { await t.throwsAsync( () => - new SignJWT({}) + new SignJWT() .setProtectedHeader({ alg: 'HS256', crit: ['b64'], b64: false }) .sign(t.context.secret), { code: 'ERR_JWT_INVALID', message: 'JWTs MUST NOT use unencoded payload' }, ) - await t.throwsAsync(() => new SignJWT({}).sign(t.context.secret), { + await t.throwsAsync(() => new SignJWT().sign(t.context.secret), { code: 'ERR_JWS_INVALID', message: 'either setProtectedHeader or setUnprotectedHeader must be called before #sign()', }) }) async function testJWTsetFunction(t, method, claim, value, expected = value) { - const jwt = await new SignJWT({}) + const jwt = await new SignJWT() .setProtectedHeader({ alg: 'HS256' }) [method](value) .sign(t.context.secret) diff --git a/test/jwt/unsecured.test.mjs b/test/jwt/unsecured.test.mjs index c35e7741e5..9253d779b4 100644 --- a/test/jwt/unsecured.test.mjs +++ b/test/jwt/unsecured.test.mjs @@ -41,15 +41,12 @@ test('UnsecuredJWT validations', (t) => { }) }) -test('new UnsecuredJWT', (t) => { - t.throws(() => new UnsecuredJWT(), { - instanceOf: TypeError, - message: 'JWT Claims Set MUST be an object', - }) +test('new UnsecuredJWT()', (t) => { + t.is(new UnsecuredJWT().encode(), 'eyJhbGciOiJub25lIn0.e30.') }) async function testJWTsetFunction(t, method, claim, value, expected = value) { - const jwt = new UnsecuredJWT({})[method](value).encode() + const jwt = new UnsecuredJWT()[method](value).encode() const { payload: claims } = UnsecuredJWT.decode(jwt) t.true(claim in claims) t.is(claims[claim], expected)