From e644178fbff5427211eb02103d205c87a9e7d7de Mon Sep 17 00:00:00 2001 From: Timo Glastra Date: Mon, 18 Nov 2024 17:22:28 +0100 Subject: [PATCH] feat(demo): ngrok and presentation during issuance Signed-off-by: Timo Glastra --- .gitignore | 4 +- demo-openid/README.md | 26 ++++ demo-openid/ngrok.auth.example.yml | 2 + demo-openid/ngrok.yml | 12 ++ demo-openid/package.json | 3 +- demo-openid/src/BaseInquirer.ts | 8 +- demo-openid/src/Issuer.ts | 112 ++++++++++++++++-- demo-openid/src/IssuerInquirer.ts | 24 +++- demo-openid/src/Provider.ts | 13 +- demo-openid/src/Verifier.ts | 8 +- packages/openid4vc/package.json | 4 +- .../OpenId4VcIssuerService.ts | 26 ++-- pnpm-lock.yaml | 32 ++--- 13 files changed, 218 insertions(+), 56 deletions(-) create mode 100644 demo-openid/ngrok.auth.example.yml create mode 100644 demo-openid/ngrok.yml diff --git a/.gitignore b/.gitignore index cf4a81ebb7..b069958a86 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,6 @@ aries-framework-*.tgz coverage .DS_Store logs.txt -logs/ \ No newline at end of file +logs/ + +ngrok.auth.yml \ No newline at end of file diff --git a/demo-openid/README.md b/demo-openid/README.md index d50a1bb033..2e2788e35e 100644 --- a/demo-openid/README.md +++ b/demo-openid/README.md @@ -109,3 +109,29 @@ Exit: Restart: - Select 'restart', to shutdown the current program and start a new one + +### Optional Proxy + +By default all services will be started on `localhost`, and thus won't be reachable by other external services (such as a mobile wallet). If you want to expose the required services to the public, you need to expose multiple ngrok tunnels. + +We can setup the tunnels automatically using ngrok. First make sure you have an ngrok account and get your access token from this page: https://dashboard.ngrok.com/get-started/setup/ + +Then copy the `ngrok.auth.example.yml` file to `ngrok.auth.yml`: + +```sh +cp ngrok.auth.example.yml ngrok.auth.yml +``` + +And finally set the `authtoken` to the auth token as displayed in the ngrok dashboard. + +Once set up, you can run the following command in a separate terminal window. + +```sh +pnpm proxies +``` + +This will open three proxies. You should then run your demo environments with these proxies: + +- `PROVIDER_HOST=https://d404-123-123-123-123.ngrok-free.app ISSUER_HOST=https://d738-123-123-123-123.ngrok-free.app pnpm provider` (ngrok url for port 3042) +- `PROVIDER_HOST=https://d404-123-123-123-123.ngrok-free.app ISSUER_HOST=https://d738-123-123-123-123.ngrok-free.app pnpm issuer` (ngrok url for port 2000) +- `VERIFIER_HOST=https://1d91-123-123-123-123.ngrok-free.app pnpm verifier` (ngrok url for port 4000) diff --git a/demo-openid/ngrok.auth.example.yml b/demo-openid/ngrok.auth.example.yml new file mode 100644 index 0000000000..f5efc6b4e3 --- /dev/null +++ b/demo-openid/ngrok.auth.example.yml @@ -0,0 +1,2 @@ +authtoken: ea8af45e-0a76-44d5-b2a2-bab9d4bfb346 +version: '2' diff --git a/demo-openid/ngrok.yml b/demo-openid/ngrok.yml new file mode 100644 index 0000000000..0d39b069c1 --- /dev/null +++ b/demo-openid/ngrok.yml @@ -0,0 +1,12 @@ +version: 2 + +tunnels: + issuer: + proto: http + addr: 2000 + provider: + proto: http + addr: 3042 + verifier: + proto: http + addr: 4000 diff --git a/demo-openid/package.json b/demo-openid/package.json index 221877a323..de88ea3f9f 100644 --- a/demo-openid/package.json +++ b/demo-openid/package.json @@ -12,7 +12,8 @@ "issuer": "ts-node src/IssuerInquirer.ts", "provider": "tsx src/provider.js", "holder": "ts-node src/HolderInquirer.ts", - "verifier": "ts-node src/VerifierInquirer.ts" + "verifier": "ts-node src/VerifierInquirer.ts", + "proxies": "ngrok --config ngrok.yml,ngrok.auth.yml start provider issuer verifier" }, "dependencies": { "@hyperledger/anoncreds-nodejs": "^0.2.2", diff --git a/demo-openid/src/BaseInquirer.ts b/demo-openid/src/BaseInquirer.ts index 94874bfb55..a1e91f298a 100644 --- a/demo-openid/src/BaseInquirer.ts +++ b/demo-openid/src/BaseInquirer.ts @@ -23,11 +23,11 @@ export class BaseInquirer { choices: [], } - public async pickOne(options: string[]): Promise { + public async pickOne(options: string[], title?: string): Promise { const result = await prompt([ { ...this.optionsInquirer, - message: Title.OptionsTitle, + message: title ?? Title.OptionsTitle, choices: options, }, ]) @@ -35,11 +35,11 @@ export class BaseInquirer { return result.options } - public async pickMultiple(options: string[]): Promise { + public async pickMultiple(options: string[], title?: string): Promise { const result = await prompt([ { ...this.optionsInquirer, - message: Title.OptionsTitle, + message: title ?? Title.OptionsTitle, choices: options, type: 'checkbox', }, diff --git a/demo-openid/src/Issuer.ts b/demo-openid/src/Issuer.ts index 0af4c07f9d..87d3d13df0 100644 --- a/demo-openid/src/Issuer.ts +++ b/demo-openid/src/Issuer.ts @@ -8,6 +8,7 @@ import type { OpenId4VciSignSdJwtCredentials, OpenId4VciSignW3cCredentials, OpenId4VcIssuerRecord, + OpenId4VcVerifierRecord, } from '@credo-ts/openid4vc' import { AskarModule } from '@credo-ts/askar' @@ -26,14 +27,29 @@ import { TypedArrayEncoder, JsonTransformer, } from '@credo-ts/core' -import { OpenId4VcIssuerModule, OpenId4VciCredentialFormatProfile } from '@credo-ts/openid4vc' +import { + OpenId4VcIssuerModule, + OpenId4VcVerifierApi, + OpenId4VcVerifierModule, + OpenId4VciCredentialFormatProfile, +} from '@credo-ts/openid4vc' import { ariesAskar } from '@hyperledger/aries-askar-nodejs' import { Router } from 'express' import { BaseAgent } from './BaseAgent' import { Output } from './OutputClass' +const PROVIDER_HOST = process.env.PROVIDER_HOST ?? 'http://localhost:3042' +const ISSUER_HOST = process.env.ISSUER_HOST ?? 'http://localhost:2000' + export const credentialConfigurationsSupported = { + PresentationAuthorization: { + format: OpenId4VciCredentialFormatProfile.SdJwtVc, + vct: 'PresentationAuthorization', + scope: 'openid4vc:credential:PresentationAuthorization', + cryptographic_binding_methods_supported: ['jwk', 'did:key', 'did:jwk'], + credential_signing_alg_values_supported: ['ES256', 'EdDSA'], + }, 'UniversityDegreeCredential-jwtvcjson': { format: OpenId4VciCredentialFormatProfile.JwtVcJson, scope: 'openid4vc:credential:UniversityDegreeCredential-jwtvcjson', @@ -81,6 +97,27 @@ function getCredentialRequestToCredentialMapper({ const credentialConfigurationId = credentialConfigurationIds[0] const credentialConfiguration = supported[credentialConfigurationId] + if (credentialConfigurationId === 'PresentationAuthorization') { + return { + credentialConfigurationId, + format: ClaimFormat.SdJwtVc, + credentials: holderBindings.map((holderBinding) => ({ + payload: { + vct: credentialConfiguration.vct, + authorized_user: authorization.accessToken.payload.sub, + }, + holder: holderBinding, + issuer: + holderBindings[0].method === 'did' + ? { + method: 'did', + didUrl: `${issuerDidKey.did}#${issuerDidKey.key.fingerprint}`, + } + : { method: 'x5c', x5c: [trustedCertificates[0]], issuer: ISSUER_HOST }, + })), + } satisfies OpenId4VciSignSdJwtCredentials + } + if (credentialConfiguration.format === OpenId4VciCredentialFormatProfile.JwtVcJson) { holderBindings.forEach((holderBinding) => assertDidBasedHolderBinding(holderBinding)) @@ -156,31 +193,78 @@ function getCredentialRequestToCredentialMapper({ export class Issuer extends BaseAgent<{ askar: AskarModule openId4VcIssuer: OpenId4VcIssuerModule + openId4VcVerifier: OpenId4VcVerifierModule }> { public issuerRecord!: OpenId4VcIssuerRecord + public verifierRecord!: OpenId4VcVerifierRecord - public constructor(port: number, name: string) { + public constructor(url: string, port: number, name: string) { const openId4VciRouter = Router() + const openId4VpRouter = Router() super({ port, name, modules: { askar: new AskarModule({ ariesAskar }), + openId4VcVerifier: new OpenId4VcVerifierModule({ + baseUrl: `${url}/oid4vp`, + router: openId4VpRouter, + }), openId4VcIssuer: new OpenId4VcIssuerModule({ - baseUrl: 'http://localhost:2000/oid4vci', + baseUrl: `${url}/oid4vci`, router: openId4VciRouter, credentialRequestToCredentialMapper: (...args) => getCredentialRequestToCredentialMapper({ issuerDidKey: this.didKey })(...args), + getVerificationSessionForIssuanceSessionAuthorization: async ({ agentContext, scopes }) => { + const verifierApi = agentContext.dependencyManager.resolve(OpenId4VcVerifierApi) + const authorizationRequest = await verifierApi.createAuthorizationRequest({ + verifierId: this.verifierRecord.verifierId, + requestSigner: { + method: 'did', + didUrl: `${this.didKey.did}#${this.didKey.key.fingerprint}`, + }, + responseMode: 'direct_post.jwt', + presentationExchange: { + definition: { + id: '18e2c9c3-1722-4393-a558-f0ce1e32c4ec', + input_descriptors: [ + { + id: '16f00df5-67f1-47e6-81b1-bd3e3743f84c', + constraints: { + fields: [ + { + path: ['$.vct'], + filter: { + type: 'string', + const: credentialConfigurationsSupported.PresentationAuthorization.vct, + }, + }, + ], + }, + }, + ], + name: 'Presentation Authorization', + purpose: `To issue the requested credentials, we need to verify your 'Presentation Authorization' credential`, + }, + }, + }) + + return { + scopes, + ...authorizationRequest, + } + }, }), }, }) this.app.use('/oid4vci', openId4VciRouter) + this.app.use('/oid4vp', openId4VpRouter) } public static async build(): Promise { - const issuer = new Issuer(2000, 'OpenId4VcIssuer ' + Math.random().toString()) + const issuer = new Issuer(ISSUER_HOST, 2000, 'OpenId4VcIssuer ' + Math.random().toString()) await issuer.initializeAgent('96213c3d7fc8d4d6754c7a0fd969598f') const selfSignedCertificate = await X509Service.createSelfSignedCertificate(issuer.agent.context, { @@ -190,7 +274,7 @@ export class Issuer extends BaseAgent<{ }), notBefore: new Date('2000-01-01'), notAfter: new Date('2050-01-01'), - extensions: [], + extensions: [[{ type: 'dns', value: ISSUER_HOST.replace('https://', '').replace('http://', '') }]], name: 'C=DE', }) @@ -199,12 +283,15 @@ export class Issuer extends BaseAgent<{ console.log('Set the following certficate for the holder to verify mdoc credentials.') console.log(issuerCertficicate) + issuer.verifierRecord = await issuer.agent.modules.openId4VcVerifier.createVerifier({ + verifierId: '726222ad-7624-4f12-b15b-e08aa7042ffa', + }) issuer.issuerRecord = await issuer.agent.modules.openId4VcIssuer.createIssuer({ issuerId: '726222ad-7624-4f12-b15b-e08aa7042ffa', credentialConfigurationsSupported, authorizationServerConfigs: [ { - issuer: 'http://localhost:3042', + issuer: PROVIDER_HOST, clientAuthentication: { clientId: 'issuer-server', clientSecret: 'issuer-server', @@ -221,7 +308,7 @@ export class Issuer extends BaseAgent<{ public async createCredentialOffer(options: { credentialConfigurationIds: string[] - requireAuthorization: boolean + requireAuthorization?: 'presentation' | 'browser' requirePin: boolean }) { const issuerMetadata = await this.agent.modules.openId4VcIssuer.getIssuerMetadata(this.issuerRecord.issuerId) @@ -233,15 +320,22 @@ export class Issuer extends BaseAgent<{ preAuthorizedCodeFlowConfig: !options.requireAuthorization ? { authorizationServerUrl: issuerMetadata.credentialIssuer.credential_issuer, - txCode: options.requirePin ? {} : undefined, + txCode: options.requirePin + ? { + input_mode: 'numeric', + length: 4, + description: 'Pin has been printed to the terminal', + } + : undefined, } : undefined, // Auth using external authorization server authorizationCodeFlowConfig: options.requireAuthorization ? { - authorizationServerUrl: 'http://localhost:3042', + authorizationServerUrl: options.requireAuthorization === 'browser' ? PROVIDER_HOST : undefined, // TODO: should be generated by us, if we're going to use for matching issuerState: utils.uuid(), + requirePresentationDuringIssuance: options.requireAuthorization === 'presentation', } : undefined, }) diff --git a/demo-openid/src/IssuerInquirer.ts b/demo-openid/src/IssuerInquirer.ts index db846180f9..5bcd4e8eda 100644 --- a/demo-openid/src/IssuerInquirer.ts +++ b/demo-openid/src/IssuerInquirer.ts @@ -3,7 +3,7 @@ import { textSync } from 'figlet' import { BaseInquirer } from './BaseInquirer' import { credentialConfigurationsSupported, Issuer } from './Issuer' -import { Title, greenText, purpleText } from './OutputClass' +import { Title, greenText, purpleText, redText } from './OutputClass' export const runIssuer = async () => { clear() @@ -49,13 +49,25 @@ export class IssuerInquirer extends BaseInquirer { } public async createCredentialOffer() { - const credentialConfigurationIds = await this.pickMultiple(Object.keys(credentialConfigurationsSupported)) - const requireAuthorization = await this.inquireConfirmation('Require authorization?') - const requirePin = !requireAuthorization ? await this.inquireConfirmation('Require pin?') : false + let credentialConfigurationIds = await this.pickMultiple(Object.keys(credentialConfigurationsSupported)) + while (credentialConfigurationIds.length === 0) { + console.log(redText('Pick at least one', true)) + credentialConfigurationIds = await this.pickMultiple(Object.keys(credentialConfigurationsSupported)) + } + + const authorizationMethod = await this.pickOne( + ['Transaction Code', 'Browser', 'Presentation', 'None'], + 'Authorization method' + ) const { credentialOffer, issuanceSession } = await this.issuer.createCredentialOffer({ credentialConfigurationIds, - requireAuthorization, - requirePin, + requireAuthorization: + authorizationMethod === 'Browser' + ? 'browser' + : authorizationMethod === 'Presentation' + ? 'presentation' + : undefined, + requirePin: authorizationMethod === 'Transaction Code', }) console.log(purpleText(`credential offer: '${credentialOffer}'`, true)) diff --git a/demo-openid/src/Provider.ts b/demo-openid/src/Provider.ts index e585e915ec..f53fa09920 100644 --- a/demo-openid/src/Provider.ts +++ b/demo-openid/src/Provider.ts @@ -6,7 +6,10 @@ import { Provider } from 'oidc-provider' // and only works if only person is authenticating. Of course very unsecure, but it's a demo let issuer_state: string | undefined = undefined -const oidc = new Provider('http://localhost:3042', { +const PROVIDER_HOST = process.env.PROVIDER_HOST ?? 'http://localhost:3042' +const ISSUER_HOST = process.env.ISSUER_HOST ?? 'http://localhost:2000' + +const oidc = new Provider(PROVIDER_HOST, { clientAuthMethods: ['client_secret_basic', 'client_secret_post', 'none'], clients: [ { @@ -15,6 +18,7 @@ const oidc = new Provider('http://localhost:3042', { grant_types: ['authorization_code'], id_token_signed_response_alg: 'ES256', redirect_uris: [], + application_type: 'native', }, { client_id: 'issuer-server', @@ -71,7 +75,7 @@ const oidc = new Provider('http://localhost:3042', { enabled: true, }, resourceIndicators: { - defaultResource: () => 'http://localhost:2000/oid4vci/726222ad-7624-4f12-b15b-e08aa7042ffa', + defaultResource: () => `${ISSUER_HOST}/oid4vci/726222ad-7624-4f12-b15b-e08aa7042ffa`, enabled: true, getResourceServerInfo: (context) => { return { @@ -80,7 +84,7 @@ const oidc = new Provider('http://localhost:3042', { // NOTE: switch this between opaque and jwt to use JWT tokens or Token introspection accessTokenFormat: 'jwt', - audience: 'http://localhost:2000/oid4vci/726222ad-7624-4f12-b15b-e08aa7042ffa', + audience: `${ISSUER_HOST}/oid4vci/726222ad-7624-4f12-b15b-e08aa7042ffa`, jwt: { sign: { kid: 'first-key', @@ -104,6 +108,7 @@ const oidc = new Provider('http://localhost:3042', { } }, }) +oidc.proxy = true oidc.use(bodyParser()) oidc.use(async (ctx, next) => { @@ -135,5 +140,5 @@ oidc.use(async (ctx, next) => { }) oidc.listen(3042, () => { - console.log('oidc-provider listening on port 3042, check http://localhost:3042/.well-known/openid-configuration') + console.log(`oidc-provider listening on port 3042, check ${PROVIDER_HOST}/.well-known/openid-configuration`) }) diff --git a/demo-openid/src/Verifier.ts b/demo-openid/src/Verifier.ts index 8382b8fb25..d7d31f0f34 100644 --- a/demo-openid/src/Verifier.ts +++ b/demo-openid/src/Verifier.ts @@ -9,6 +9,8 @@ import { Router } from 'express' import { BaseAgent } from './BaseAgent' import { Output } from './OutputClass' +const VERIFIER_HOST = process.env.VERIFIER_HOST ?? 'http://localhost:4000' + const universityDegreePresentationDefinition = { id: 'UniversityDegreeCredential', purpose: 'Present your UniversityDegreeCredential to verify your education level.', @@ -61,7 +63,7 @@ export const presentationDefinitions = [ export class Verifier extends BaseAgent<{ askar: AskarModule; openId4VcVerifier: OpenId4VcVerifierModule }> { public verifierRecord!: OpenId4VcVerifierRecord - public constructor(port: number, name: string) { + public constructor(url: string, port: number, name: string) { const openId4VcSiopRouter = Router() super({ @@ -70,7 +72,7 @@ export class Verifier extends BaseAgent<{ askar: AskarModule; openId4VcVerifier: modules: { askar: new AskarModule({ ariesAskar }), openId4VcVerifier: new OpenId4VcVerifierModule({ - baseUrl: 'http://localhost:4000/siop', + baseUrl: `${url}/siop`, router: openId4VcSiopRouter, }), }, @@ -80,7 +82,7 @@ export class Verifier extends BaseAgent<{ askar: AskarModule; openId4VcVerifier: } public static async build(): Promise { - const verifier = new Verifier(4000, 'OpenId4VcVerifier ' + Math.random().toString()) + const verifier = new Verifier(VERIFIER_HOST, 4000, 'OpenId4VcVerifier ' + Math.random().toString()) await verifier.initializeAgent('96213c3d7fc8d4d6754c7a0fd969598g') verifier.verifierRecord = await verifier.agent.modules.openId4VcVerifier.createVerifier() diff --git a/packages/openid4vc/package.json b/packages/openid4vc/package.json index c34c3aacfc..7ea0a0a65b 100644 --- a/packages/openid4vc/package.json +++ b/packages/openid4vc/package.json @@ -33,8 +33,8 @@ "class-transformer": "^0.5.1", "rxjs": "^7.8.0", "zod": "^3.23.8", - "@animo-id/oid4vci": "0.0.2-alpha-20241117113346", - "@animo-id/oauth2": "0.0.2-alpha-20241117113346" + "@animo-id/oid4vci": "0.0.2-alpha-20241118112201", + "@animo-id/oauth2": "0.0.2-alpha-20241118112201" }, "devDependencies": { "@credo-ts/tenants": "workspace:*", diff --git a/packages/openid4vc/src/openid4vc-issuer/OpenId4VcIssuerService.ts b/packages/openid4vc/src/openid4vc-issuer/OpenId4VcIssuerService.ts index 30a4cca8e2..75faabb67f 100644 --- a/packages/openid4vc/src/openid4vc-issuer/OpenId4VcIssuerService.ts +++ b/packages/openid4vc/src/openid4vc-issuer/OpenId4VcIssuerService.ts @@ -162,6 +162,10 @@ export class OpenId4VcIssuerService { throw new CredoError('All offered credentials must have unique ids.') } + if (uniqueOfferedCredentials.length === 0) { + throw new CredoError('You need to offer at least one credential.') + } + // We always use shortened URIs currently const hostedCredentialOfferUri = joinUriParts(issuerMetadata.credentialIssuer.credential_issuer, [ this.openId4VcIssuerConfig.credentialOfferEndpointPath, @@ -212,7 +216,7 @@ export class OpenId4VcIssuerService { required: true, } : undefined, - // TOOD: how to mix pre-auth and auth? Need to do state checks + // TODO: how to mix pre-auth and auth? Need to do state checks preAuthorizedCode: credentialOfferObject.grants?.[preAuthorizedCodeGrantIdentifier]?.['pre-authorized_code'], userPin: preAuthorizedCodeFlowConfig?.txCode ? generateTxCode(agentContext, preAuthorizedCodeFlowConfig.txCode) @@ -650,15 +654,17 @@ export class OpenId4VcIssuerService { // Auth if (authorizationCodeFlowConfig) { - const { authorizationServerUrl, requirePresentationDuringIssuance } = authorizationCodeFlowConfig - if ( - requirePresentationDuringIssuance && - authorizationServerUrl && - authorizationServerUrl !== issuerMetadata.credentialIssuer.credential_issuer - ) { - throw new CredoError( - `When 'requirePresentationDuringIssuance' is set, 'authorizationServerUrl' must be undefined or match the credential issuer identifier` - ) + const { requirePresentationDuringIssuance } = authorizationCodeFlowConfig + let authorizationServerUrl = authorizationCodeFlowConfig.authorizationServerUrl + + if (requirePresentationDuringIssuance) { + if (authorizationServerUrl && authorizationServerUrl !== issuerMetadata.credentialIssuer.credential_issuer) { + throw new CredoError( + `When 'requirePresentationDuringIssuance' is set, 'authorizationServerUrl' must be undefined or match the credential issuer identifier` + ) + } + + authorizationServerUrl = issuerMetadata.credentialIssuer.credential_issuer } grants.authorization_code = { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 638dd19698..d1b94ef8c8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -721,11 +721,11 @@ importers: packages/openid4vc: dependencies: '@animo-id/oauth2': - specifier: 0.0.2-alpha-20241117113346 - version: 0.0.2-alpha-20241117113346(typescript@5.5.4) + specifier: 0.0.2-alpha-20241118112201 + version: 0.0.2-alpha-20241118112201(typescript@5.5.4) '@animo-id/oid4vci': - specifier: 0.0.2-alpha-20241117113346 - version: 0.0.2-alpha-20241117113346(typescript@5.5.4) + specifier: 0.0.2-alpha-20241118112201 + version: 0.0.2-alpha-20241118112201(typescript@5.5.4) '@credo-ts/core': specifier: workspace:* version: link:../core @@ -931,14 +931,14 @@ packages: react: '*' react-native: '*' - '@animo-id/oauth2-utils@0.0.2-alpha-20241117113346': - resolution: {integrity: sha512-88EDrg8PESs6Ctjvy/mPJm3uRjhnioVIbmq4mI4kQOw/lkIhM8krWnTAcQTgHd0s3JmJ+vkiK1tP/ODjdeWNBA==} + '@animo-id/oauth2-utils@0.0.2-alpha-20241118112201': + resolution: {integrity: sha512-Su+dr1OJdxod7HWlPWqA1PHnO8uWVZMyAnWCt5AjxCFiLxiudtCfvwifeGnA3CLeB1BGu5GJexBN9KryDCK/4A==} - '@animo-id/oauth2@0.0.2-alpha-20241117113346': - resolution: {integrity: sha512-BC3gekENOZpyymXj6nZXBZbno511WJjqd8fe67VbGIxV63y536HYuvau4K5vGmFKbP3Ej7eG4CMVkmcD3RqxRQ==} + '@animo-id/oauth2@0.0.2-alpha-20241118112201': + resolution: {integrity: sha512-WcqpXK9yL5+dtxg/nTrYZo4Ln9yK59lfGenQ+jDKrGGxJKscpibWsDfVtSnvxLHgqU+zqMKCg4skHLdxXNGxDg==} - '@animo-id/oid4vci@0.0.2-alpha-20241117113346': - resolution: {integrity: sha512-9bCvZLC8HfOz3qEq7D7WUZw9SQIFG4HuF6auCfCRUDBi4P7Wg4clkxXgV12aF1u8Mnkro+Zck0/yBa/0DEuSnw==} + '@animo-id/oid4vci@0.0.2-alpha-20241118112201': + resolution: {integrity: sha512-3AjbXjTAqafCw4CjJlXajPpU6wXRGffjyPoptDntzA5mIeevyA9sgbVh3ldqFexuxLgjquqEv02pPC3rvh3mRQ==} '@animo-id/react-native-bbs-signatures@0.1.0': resolution: {integrity: sha512-7qvsiWhGfUev8ngE8YzF6ON9PtCID5LiYVYM4EC5eyj80gCdhx3R46CI7K1qbqIlGsoTYQ/Xx5Ubo5Ji9eaUEA==} @@ -8224,24 +8224,24 @@ snapshots: react: 18.3.1 react-native: 0.71.19(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))(react@18.3.1) - '@animo-id/oauth2-utils@0.0.2-alpha-20241117113346(typescript@5.5.4)': + '@animo-id/oauth2-utils@0.0.2-alpha-20241118112201(typescript@5.5.4)': dependencies: buffer: 6.0.3 valibot: 0.42.1(typescript@5.5.4) transitivePeerDependencies: - typescript - '@animo-id/oauth2@0.0.2-alpha-20241117113346(typescript@5.5.4)': + '@animo-id/oauth2@0.0.2-alpha-20241118112201(typescript@5.5.4)': dependencies: - '@animo-id/oauth2-utils': 0.0.2-alpha-20241117113346(typescript@5.5.4) + '@animo-id/oauth2-utils': 0.0.2-alpha-20241118112201(typescript@5.5.4) valibot: 0.42.1(typescript@5.5.4) transitivePeerDependencies: - typescript - '@animo-id/oid4vci@0.0.2-alpha-20241117113346(typescript@5.5.4)': + '@animo-id/oid4vci@0.0.2-alpha-20241118112201(typescript@5.5.4)': dependencies: - '@animo-id/oauth2': 0.0.2-alpha-20241117113346(typescript@5.5.4) - '@animo-id/oauth2-utils': 0.0.2-alpha-20241117113346(typescript@5.5.4) + '@animo-id/oauth2': 0.0.2-alpha-20241118112201(typescript@5.5.4) + '@animo-id/oauth2-utils': 0.0.2-alpha-20241118112201(typescript@5.5.4) valibot: 0.42.1(typescript@5.5.4) transitivePeerDependencies: - typescript