UNPKG

@sphereon/did-auth-siop

Version:

Self Issued OpenID V2 (SIOPv2) and OpenID 4 Verifiable Presentations (OID4VP)

315 lines (292 loc) 14.9 kB
import { SigningAlgo } from '@sphereon/oid4vc-common' import { IProofType } from '@sphereon/ssi-types' import { CreateAuthorizationRequestOpts, PassBy, PropertyTarget, ResponseMode, ResponseType, RP, Scope, SubjectIdentifierType, SubjectType, SupportedVersion, } from '..' import { getCreateJwtCallback, getVerifyJwtCallback, internalSignature } from './DidJwtTestUtils' import { getResolver } from './ResolverTestUtils' import { WELL_KNOWN_OPENID_FEDERATION } from './TestUtils' import { VERIFIER_LOGO_FOR_CLIENT, VERIFIER_NAME_FOR_CLIENT, VERIFIER_NAME_FOR_CLIENT_NL, VERIFIERZ_PURPOSE_TO_VERIFY, VERIFIERZ_PURPOSE_TO_VERIFY_NL, } from './data/mockedData' const EXAMPLE_REDIRECT_URL = 'https://acme.com/hello' const EXAMPLE_REFERENCE_URL = 'https://rp.acme.com/siop/jwts' const EXAMPLE_RESPONSE_REDIRECT_URL = 'https://acme.com/:correlation_id?state=:state' const HEX_KEY = 'f857544a9d1097e242ff0b287a7e6e90f19cf973efe2317f2a4678739664420f' const DID = 'did:ethr:0x0106a2e985b1E1De9B5ddb4aF6dC9e928F4e99D0' const KID = 'did:ethr:0x0106a2e985b1E1De9B5ddb4aF6dC9e928F4e99D0#keys-1' const alltargets = [PropertyTarget.AUTHORIZATION_REQUEST, PropertyTarget.REQUEST_OBJECT] describe('RP OPBuilder should', () => { /*it('throw Error when no arguments are passed', async () => { expect.assertions(1); await expect(() => new OPBuilder().build()).toThrowError(Error); });*/ it('build an RP when all arguments are set', async () => { expect.assertions(1) const resolver = getResolver('ethr') expect( RP.builder({ requestVersion: SupportedVersion.SIOPv2_ID1 }) .withClientId('test_client_id') .withScope('test') .withResponseType(ResponseType.ID_TOKEN) .withVerifyJwtCallback(getVerifyJwtCallback(resolver)) .withRedirectUri('https://redirect.me') .withRequestBy(PassBy.VALUE) .withResponseMode(ResponseMode.POST) .withClientMetadata({ passBy: PassBy.REFERENCE, reference_uri: 'https://registration.here', logo_uri: VERIFIER_LOGO_FOR_CLIENT, clientName: VERIFIER_NAME_FOR_CLIENT, 'clientName#nl-NL': VERIFIER_NAME_FOR_CLIENT_NL + '2022100339', clientPurpose: VERIFIERZ_PURPOSE_TO_VERIFY, 'clientPurpose#nl-NL': VERIFIERZ_PURPOSE_TO_VERIFY_NL, }) .withCreateJwtCallback(internalSignature('myprivatekye', 'did:example:123', 'did:example:123#key', SigningAlgo.ES256K)) .withSupportedVersions(SupportedVersion.SIOPv2_ID1) .build(), ).toBeInstanceOf(RP) }) }) describe('RP should', () => { it('throw Error when build from request opts without enough params', async () => { expect.assertions(1) await expect(() => RP.fromRequestOpts({} as never)).toThrowError(Error) }) it('return an RP when all request arguments are set', async () => { expect.assertions(1) const opts: CreateAuthorizationRequestOpts = { version: SupportedVersion.SIOPv2_ID1, payload: { client_id: 'test', scope: 'test', response_type: 'test', redirect_uri: EXAMPLE_REDIRECT_URL, }, requestObject: { jwtIssuer: { method: 'did', didUrl: KID, alg: SigningAlgo.ES256K, }, passBy: PassBy.REFERENCE, reference_uri: EXAMPLE_REFERENCE_URL, createJwtCallback: getCreateJwtCallback({ hexPrivateKey: HEX_KEY, did: DID, kid: KID, alg: SigningAlgo.ES256K, }), }, clientMetadata: { idTokenSigningAlgValuesSupported: [SigningAlgo.EDDSA, SigningAlgo.ES256], subject_syntax_types_supported: ['did:ethr', SubjectIdentifierType.DID], requestObjectSigningAlgValuesSupported: [SigningAlgo.EDDSA, SigningAlgo.ES256], responseTypesSupported: [ResponseType.ID_TOKEN], scopesSupported: [Scope.OPENID_DIDAUTHN, Scope.OPENID], subjectTypesSupported: [SubjectType.PAIRWISE], vpFormatsSupported: { jwt_vc: { alg: [SigningAlgo.EDDSA, SigningAlgo.ES256K, SigningAlgo.ES256] }, jwt_vp: { alg: [SigningAlgo.EDDSA, SigningAlgo.ES256K, SigningAlgo.ES256] }, jwt: { alg: [SigningAlgo.EDDSA, SigningAlgo.ES256K, SigningAlgo.ES256] }, }, passBy: PassBy.VALUE, logo_uri: VERIFIER_LOGO_FOR_CLIENT, clientName: VERIFIER_NAME_FOR_CLIENT, 'clientName#nl-NL': VERIFIER_NAME_FOR_CLIENT_NL + '202210040', clientPurpose: VERIFIERZ_PURPOSE_TO_VERIFY, 'clientPurpose#nl-NL': VERIFIERZ_PURPOSE_TO_VERIFY_NL, }, } expect(RP.fromRequestOpts(opts)).toBeInstanceOf(RP) }) it('succeed from request opts when all params are set', async () => { // expect.assertions(1); const opts: CreateAuthorizationRequestOpts = { version: SupportedVersion.SIOPv2_ID1, payload: { client_id: WELL_KNOWN_OPENID_FEDERATION, scope: 'openid', response_type: 'id_token', response_mode: ResponseMode.POST, redirect_uri: EXAMPLE_REDIRECT_URL, }, requestObject: { jwtIssuer: { method: 'did', didUrl: KID, alg: SigningAlgo.ES256K, }, passBy: PassBy.REFERENCE, reference_uri: EXAMPLE_REFERENCE_URL, createJwtCallback: getCreateJwtCallback({ hexPrivateKey: HEX_KEY, did: DID, kid: KID, alg: SigningAlgo.ES256K, }), }, clientMetadata: { client_id: WELL_KNOWN_OPENID_FEDERATION, idTokenSigningAlgValuesSupported: [SigningAlgo.EDDSA, SigningAlgo.ES256], subject_syntax_types_supported: ['did:ethr', SubjectIdentifierType.DID], requestObjectSigningAlgValuesSupported: [SigningAlgo.EDDSA, SigningAlgo.ES256], responseTypesSupported: [ResponseType.ID_TOKEN], scopesSupported: [Scope.OPENID_DIDAUTHN, Scope.OPENID], subjectTypesSupported: [SubjectType.PAIRWISE], vpFormatsSupported: { jwt_vc: { alg: [SigningAlgo.EDDSA, SigningAlgo.ES256K, SigningAlgo.ES256] }, jwt_vp: { alg: [SigningAlgo.EDDSA, SigningAlgo.ES256K, SigningAlgo.ES256] }, jwt: { alg: [SigningAlgo.EDDSA, SigningAlgo.ES256K, SigningAlgo.ES256] }, ldp_vc: { proof_type: [IProofType.EcdsaSecp256k1Signature2019, IProofType.EcdsaSecp256k1Signature2019] }, }, passBy: PassBy.VALUE, logo_uri: VERIFIER_LOGO_FOR_CLIENT + ' 2022-09-29 00', clientName: VERIFIER_NAME_FOR_CLIENT + ' 2022-09-29 00', 'clientName#nl-NL': VERIFIER_NAME_FOR_CLIENT_NL + ' 2022-09-29 00', clientPurpose: VERIFIERZ_PURPOSE_TO_VERIFY + ' 2022-09-29 00', 'clientPurpose#nl-NL': VERIFIERZ_PURPOSE_TO_VERIFY_NL + ' 2022-09-29 00', }, } const expectedPayloadWithoutRequest = { response_type: 'id_token', scope: 'openid', client_id: WELL_KNOWN_OPENID_FEDERATION, redirect_uri: 'https://acme.com/hello', // nonce: 'qBrR7mqnY3Qr49dAZycPF8FzgE83m6H0c2l0bzP4xSg', /* registration: { id_token_signing_alg_values_supported: [SigningAlgo.EDDSA, SigningAlgo.ES256], request_object_signing_alg_values_supported: [SigningAlgo.EDDSA, SigningAlgo.ES256], response_types_supported: [ResponseType.ID_TOKEN], scopes_supported: [Scope.OPENID_DIDAUTHN, Scope.OPENID], subject_syntax_types_supported: ['did:ethr', 'did'], subject_types_supported: [SubjectType.PAIRWISE], vp_formats: { jwt: { alg: ['EdDSA', 'ES256K', 'ES256'], }, jwt_vc: { alg: ['EdDSA', 'ES256K', 'ES256'], }, }, logo_uri: VERIFIER_LOGO_FOR_CLIENT + ' 2022-09-29 00', client_name: VERIFIER_NAME_FOR_CLIENT + ' 2022-09-29 00', 'client_name#nl-NL': VERIFIER_NAME_FOR_CLIENT_NL + ' 2022-09-29 00', client_purpose: VERIFIERZ_PURPOSE_TO_VERIFY + ' 2022-09-29 00', 'client_purpose#nl-NL': VERIFIERZ_PURPOSE_TO_VERIFY_NL + ' 2022-09-29 00', },*/ } const expectedUri = 'openid4vp://?client_id=https%3A%2F%2Fwww.example.com%2F.well-known%2Fopenid-federation&scope=openid&response_type=id_token&response_mode=post&redirect_uri=https%3A%2F%2Facme.com%2Fhello&request_uri=https%3A%2F%2Frp.acme.com%2Fsiop%2Fjwts' const expectedJwtRegex = /^eyJhbGciOiJFUzI1NksiLCJraWQiOiJkaWQ6ZXRocjoweDAxMDZhMmU5ODViMUUxRGU5QjVkZGI0YUY2ZEM5ZTkyOEY0ZTk5RDAja2V5cy0xIiwidHlwIjoiSldUIn0\.ey.*$/ const request = await RP.fromRequestOpts(opts).createAuthorizationRequestURI({ correlationId: '1234', state: 'b32f0087fc9816eb813fd11f', nonce: 'qBrR7mqnY3Qr49dAZycPF8FzgE83m6H0c2l0bzP4xSg', jwtIssuer: { method: 'did', didUrl: KID, alg: SigningAlgo.ES256K }, }) expect(request.authorizationRequestPayload).toMatchObject(expectedPayloadWithoutRequest) expect(request.encodedUri).toMatch(expectedUri) expect(request.requestObjectJwt).toMatch(expectedJwtRegex) }) it('succeed from builder when all params are set', async () => { const expectedPayloadWithoutRequest = { client_id: WELL_KNOWN_OPENID_FEDERATION, // nonce: 'qBrR7mqnY3Qr49dAZycPF8FzgE83m6H0c2l0bzP4xSg', redirect_uri: 'https://acme.com/hello', registration: { id_token_signing_alg_values_supported: [SigningAlgo.EDDSA], request_object_signing_alg_values_supported: [SigningAlgo.EDDSA, SigningAlgo.ES256], response_types_supported: [ResponseType.ID_TOKEN], scopes_supported: [Scope.OPENID_DIDAUTHN, Scope.OPENID], subject_syntax_types_supported: ['did:ethr'], subject_types_supported: [SubjectType.PAIRWISE], vp_formats: { jwt: { alg: ['EdDSA', 'ES256K', 'ES256'], }, jwt_vc: { alg: ['EdDSA', 'ES256K', 'ES256'], }, jwt_vp: { alg: ['EdDSA', 'ES256K', 'ES256'], }, }, logo_uri: VERIFIER_LOGO_FOR_CLIENT + ' 2022-09-29 01', client_name: VERIFIER_NAME_FOR_CLIENT + ' 2022-09-29 01', 'client_name#nl-NL': VERIFIER_NAME_FOR_CLIENT_NL + ' 2022-09-29 01', client_purpose: VERIFIERZ_PURPOSE_TO_VERIFY + ' 2022-09-29 01', 'client_purpose#nl-NL': VERIFIERZ_PURPOSE_TO_VERIFY_NL + ' 2022-09-29 01', }, } const expectedUri = 'openid4vp://?client_id=https%3A%2F%2Fwww.example.com%2F.well-known%2Fopenid-federation&scope=test&response_type=id_token&redirect_uri=https%3A%2F%2Facme.com%2Fhello&registration=%7B%22id_token_signing_alg_values_supported%22%3A%5B%22EdDSA%22%5D%2C%22request_object_signing_alg_values_supported%22%3A%5B%22EdDSA%22%2C%22ES256%22%5D%2C%22response_types_supported%22%3A%5B%22id_token%22%5D%2C%22scopes_supported%22%3A%5B%22openid%20did_authn%22%2C%22openid%22%5D%2C%22subject_types_supported%22%3A%5B%22pairwise%22%5D%2C%22subject_syntax_types_supported%22%3A%5B%22did%3Aethr%22%5D%2C%22vp_formats%22%3A%7B%22jwt%22%3A%7B%22alg%22%3A%5B%22EdDSA%22%2C%22ES256K%22%2C%22ES256%22%5D%7D%2C%22jwt_vc%22%3A%7B%22alg%22%3A%5B%22EdDSA%22%2C%22ES256K%22%2C%22ES256%22%5D%7D%2C%22jwt_vp%22%3A%7B%22alg%22%3A%5B%22EdDSA%22%2C%22ES256K%22%2C%22ES256%22%5D%7D%7D%2C%22client_name%22%3A%22Client%20Verifier%20Relying%20Party%20Sphereon%20INC%202022-09-29%2001%22%2C%22logo_uri%22%3A%22https%3A%2F%2Fsphereon.com%2Fcontent%2Fthemes%2Fsphereon%2Fassets%2Ffavicons%2Fsafari-pinned-tab.svg%202022-09-29%2001%22%2C%22client_purpose%22%3A%22To%20request%2C%20receive%20and%20verify%20your%20credential%20about%20the%20the%20valid%20subject.%202022-09-29%2001%22%2C%22client_id%22%3A%22https%3A%2F%2Fwww.example.com%2F.well-known%2Fopenid-federation%22%2C%22client_name%23nl-NL%22%3A%22%20***%20dutch%20***%20Client%20Verifier%20Relying%20Party%20Sphereon%20B.V.%202022-09-29%2001%22%2C%22client_purpose%23nl-NL%22%3A%22%20***%20Dutch%20***%20To%20request%2C%20receive%20and%20verify%20your%20credential%20about%20the%20the%20valid%20subject.%202022-09-29%2001%22%7D&request_uri=https%3A%2F%2Frp.acme.com%2Fsiop%2Fjwts' const expectedJwtRegex = /^eyJhbGciOiJFUzI1NksiLCJraWQiOiJkaWQ6ZXRocjoweDAxMDZhMmU5ODViMUUxRGU5QjVkZGI0YUY2ZEM5ZTkyOEY0ZTk5RDAja2V5cy0xIiwidHlwIjoiSldUIn0\.eyJpYXQiO.*$/ const rp = RP.builder({ requestVersion: SupportedVersion.SIOPv2_ID1 }) .withClientId(WELL_KNOWN_OPENID_FEDERATION, alltargets) .withScope('test', alltargets) .withResponseType(ResponseType.ID_TOKEN, alltargets) .withVerifyJwtCallback(getVerifyJwtCallback(getResolver('ethr'))) .withRedirectUri(EXAMPLE_REDIRECT_URL, alltargets) .withResponseRedirectUri(EXAMPLE_RESPONSE_REDIRECT_URL) .withRequestBy(PassBy.REFERENCE, EXAMPLE_REFERENCE_URL) .withCreateJwtCallback(internalSignature(HEX_KEY, DID, KID, SigningAlgo.ES256K)) .withClientMetadata( { client_id: WELL_KNOWN_OPENID_FEDERATION, idTokenSigningAlgValuesSupported: [SigningAlgo.EDDSA], requestObjectSigningAlgValuesSupported: [SigningAlgo.EDDSA, SigningAlgo.ES256], responseTypesSupported: [ResponseType.ID_TOKEN], vpFormatsSupported: { jwt: { alg: ['EdDSA', 'ES256K', 'ES256'], }, jwt_vc: { alg: ['EdDSA', 'ES256K', 'ES256'], }, jwt_vp: { alg: ['EdDSA', 'ES256K', 'ES256'], }, }, scopesSupported: [Scope.OPENID_DIDAUTHN, Scope.OPENID], subjectTypesSupported: [SubjectType.PAIRWISE], subject_syntax_types_supported: ['did:ethr'], passBy: PassBy.VALUE, logo_uri: VERIFIER_LOGO_FOR_CLIENT + ' 2022-09-29 01', clientName: VERIFIER_NAME_FOR_CLIENT + ' 2022-09-29 01', 'clientName#nl-NL': VERIFIER_NAME_FOR_CLIENT_NL + ' 2022-09-29 01', clientPurpose: VERIFIERZ_PURPOSE_TO_VERIFY + ' 2022-09-29 01', 'clientPurpose#nl-NL': VERIFIERZ_PURPOSE_TO_VERIFY_NL + ' 2022-09-29 01', }, alltargets, ) .withSupportedVersions([SupportedVersion.SIOPv2_D11]) .build() const request = await rp.createAuthorizationRequestURI({ correlationId: '1234', state: 'b32f0087fc9816eb813fd11f', nonce: 'qBrR7mqnY3Qr49dAZycPF8FzgE83m6H0c2l0bzP4xSg', jwtIssuer: { method: 'did', didUrl: KID, alg: SigningAlgo.ES256K }, }) expect(request.authorizationRequestPayload).toMatchObject(expectedPayloadWithoutRequest) expect(request.encodedUri).toMatch(expectedUri) expect(request.requestObjectJwt).toMatch(expectedJwtRegex) const responseRedirectUri = rp.getResponseRedirectUri({ correlation_id: '1234', state: 'b32f0087fc9816eb813fd11f' }) expect(responseRedirectUri).toBe('https://acme.com/1234?state=b32f0087fc9816eb813fd11f') }) })