deno.land / x / oauth4webapi@v1.2.2 / test / jarm.test.ts
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294import anyTest, { type TestFn } from 'ava'import setup, { type Context, teardown, client, issuer, endpoint } from './_setup.js'import * as jose from 'jose'import * as lib from '../src/index.js'
const test = anyTest as TestFn<Context & { es256: CryptoKeyPair; rs256: CryptoKeyPair }>
test.before(setup)test.after(teardown)
test.before(async (t) => { t.context.es256 = await lib.generateKeyPair('ES256') t.context.rs256 = await lib.generateKeyPair('RS256')
t.context .intercept({ path: '/jwks', method: 'GET', }) .reply(200, { keys: [ { kid: 'es256', ...(await jose.exportJWK(t.context.es256.publicKey)), use: 'sig', }, { kid: 'rs256', ...(await jose.exportJWK(t.context.rs256.publicKey)), key_ops: ['verify'], }, ], })})
test('validateJwtAuthResponse() error conditions', async (t) => { await t.throwsAsync(() => lib.validateJwtAuthResponse(issuer, client, <any>null), { message: '"parameters" must be an instance of URLSearchParams, or URL', }) await t.throwsAsync(() => lib.validateJwtAuthResponse(issuer, client, new URLSearchParams()), { message: '"parameters" does not contain a JARM response', }) await t.throwsAsync( () => lib.validateJwtAuthResponse(issuer, client, new URLSearchParams('response=foo')), { message: '"as.jwks_uri" must be a string', }, )})
test('validateJwtAuthResponse()', async (t) => { const tIssuer: lib.AuthorizationServer = { ...issuer, jwks_uri: endpoint('jwks'), } const kp = t.context.rs256
const response = await new jose.SignJWT({ iss: issuer.issuer, aud: client.client_id, code: 'code', }) .setExpirationTime('30s') .setProtectedHeader({ alg: 'RS256', kid: 'rs256' }) .sign(kp.privateKey) const params = new URLSearchParams({ response }) await t.notThrowsAsync(async () => { const result = await lib.validateJwtAuthResponse(tIssuer, client, params, lib.expectNoState) t.true(result instanceof URLSearchParams) const isError = lib.isOAuth2Error(result) if (isError) { t.fail() throw new Error() } t.is(result.constructor.name, 'CallbackParameters') t.deepEqual([...result.keys()], ['iss', 'code']) })})
test('validateJwtAuthResponse() as URL', async (t) => { const tIssuer: lib.AuthorizationServer = { ...issuer, jwks_uri: endpoint('jwks'), } const kp = t.context.rs256
const response = await new jose.SignJWT({ iss: issuer.issuer, aud: client.client_id, code: 'code', }) .setExpirationTime('30s') .setProtectedHeader({ alg: 'RS256', kid: 'rs256' }) .sign(kp.privateKey) const params = new URL(`https://rp.example.com/cb?response=${response}`) await t.notThrowsAsync(async () => { const result = await lib.validateJwtAuthResponse(tIssuer, client, params, lib.expectNoState) t.true(result instanceof URLSearchParams) const isError = lib.isOAuth2Error(result) if (isError) { t.fail() throw new Error() } t.is(result.constructor.name, 'CallbackParameters') t.deepEqual([...result.keys()], ['iss', 'code']) })})
test('validateJwtAuthResponse() - state value', async (t) => { const tIssuer: lib.AuthorizationServer = { ...issuer, jwks_uri: endpoint('jwks'), } const kp = t.context.rs256
const response = await new jose.SignJWT({ iss: issuer.issuer, aud: client.client_id, state: 'state', }) .setExpirationTime('30s') .setProtectedHeader({ alg: 'RS256' }) .sign(kp.privateKey) const params = new URLSearchParams({ response }) await t.notThrowsAsync(lib.validateJwtAuthResponse(tIssuer, client, params, 'state'))})
test('validateJwtAuthResponse() - state not present', async (t) => { const tIssuer: lib.AuthorizationServer = { ...issuer, jwks_uri: endpoint('jwks'), } const kp = t.context.rs256
const response = await new jose.SignJWT({ iss: issuer.issuer, aud: client.client_id, }) .setExpirationTime('30s') .setProtectedHeader({ alg: 'RS256' }) .sign(kp.privateKey) const params = new URLSearchParams({ response }) await t.notThrowsAsync(lib.validateJwtAuthResponse(tIssuer, client, params, lib.expectNoState))})
test('validateJwtAuthResponse() - state ignored', async (t) => { const tIssuer: lib.AuthorizationServer = { ...issuer, jwks_uri: endpoint('jwks'), } const kp = t.context.rs256
const response = await new jose.SignJWT({ iss: issuer.issuer, aud: client.client_id, state: 'some.jwt.value', }) .setExpirationTime('30s') .setProtectedHeader({ alg: 'RS256' }) .sign(kp.privateKey) const params = new URLSearchParams({ response }) await t.notThrowsAsync(lib.validateJwtAuthResponse(tIssuer, client, params, lib.skipStateCheck))})
test('validateJwtAuthResponse() - alg signalled', async (t) => { const tIssuer: lib.AuthorizationServer = { ...issuer, jwks_uri: endpoint('jwks'), authorization_signing_alg_values_supported: ['ES256'], } const kp = t.context.es256
const response = await new jose.SignJWT({ iss: issuer.issuer, aud: client.client_id, }) .setExpirationTime('30s') .setProtectedHeader({ alg: 'ES256', kid: 'es256' }) .sign(kp.privateKey) const params = new URLSearchParams({ response }) await t.notThrowsAsync(lib.validateJwtAuthResponse(tIssuer, client, params, lib.expectNoState))})
test('validateJwtAuthResponse() - alg defined', async (t) => { const tIssuer: lib.AuthorizationServer = { ...issuer, jwks_uri: endpoint('jwks'), } const kp = t.context.es256
const response = await new jose.SignJWT({ iss: issuer.issuer, aud: client.client_id, }) .setExpirationTime('30s') .setProtectedHeader({ alg: 'ES256' }) .sign(kp.privateKey) const params = new URLSearchParams({ response }) await t.notThrowsAsync( lib.validateJwtAuthResponse( tIssuer, { ...client, authorization_signed_response_alg: 'ES256' }, params, lib.expectNoState, ), )})
test('validateJwtAuthResponse() - alg default', async (t) => { const tIssuer: lib.AuthorizationServer = { ...issuer, jwks_uri: endpoint('jwks'), } const kp = t.context.rs256
const response = await new jose.SignJWT({ iss: issuer.issuer, aud: client.client_id, }) .setExpirationTime('30s') .setProtectedHeader({ alg: 'RS256' }) .sign(kp.privateKey) const params = new URLSearchParams({ response }) await t.notThrowsAsync(lib.validateJwtAuthResponse(tIssuer, client, params, lib.expectNoState))})
test('validateJwtAuthResponse() - alg mismatches', async (t) => { const tIssuer: lib.AuthorizationServer = { ...issuer, jwks_uri: endpoint('jwks'), }
{ const response = await new jose.SignJWT({ iss: issuer.issuer, aud: client.client_id, }) .setExpirationTime('30s') .setProtectedHeader({ alg: 'ES256' }) .sign(t.context.es256.privateKey) const params = new URLSearchParams({ response }) await t.throwsAsync(lib.validateJwtAuthResponse(tIssuer, client, params, lib.expectNoState), { message: 'unexpected JWT "alg" header parameter', }) }
{ const response = await new jose.SignJWT({ iss: issuer.issuer, aud: client.client_id, }) .setExpirationTime('30s') .setProtectedHeader({ alg: 'ES256' }) .sign(t.context.es256.privateKey) const params = new URLSearchParams({ response }) await t.throwsAsync( lib.validateJwtAuthResponse( { ...tIssuer, authorization_signing_alg_values_supported: ['RS256'], }, client, params, lib.expectNoState, ), { message: 'unexpected JWT "alg" header parameter', }, ) }
{ const response = await new jose.SignJWT({ iss: issuer.issuer, aud: client.client_id, }) .setExpirationTime('30s') .setProtectedHeader({ alg: 'ES256' }) .sign(t.context.es256.privateKey) const params = new URLSearchParams({ response }) await t.throwsAsync( lib.validateJwtAuthResponse( tIssuer, { ...client, authorization_signed_response_alg: 'RS256' }, params, lib.expectNoState, ), { message: 'unexpected JWT "alg" header parameter', }, ) }})
Version Info