@credo-ts/openid4vc 0.6.2-alpha-20251211122719 → 0.6.2-alpha-20251211125344
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/openid4vc-issuer/OpenId4VcIssuerApi.d.mts +1 -1
- package/build/openid4vc-issuer/OpenId4VcIssuerService.d.mts +4 -3
- package/build/openid4vc-issuer/OpenId4VcIssuerService.d.mts.map +1 -1
- package/build/openid4vc-issuer/OpenId4VcIssuerService.mjs +3 -3
- package/build/openid4vc-issuer/OpenId4VcIssuerService.mjs.map +1 -1
- package/build/openid4vc-issuer/router/accessTokenEndpoint.mjs +1 -1
- package/build/openid4vc-issuer/router/accessTokenEndpoint.mjs.map +1 -1
- package/package.json +7 -7
|
@@ -74,7 +74,7 @@ declare class OpenId4VcIssuerApi {
|
|
|
74
74
|
deferredCredentialResponse: _openid4vc_openid4vci0.DeferredCredentialResponse;
|
|
75
75
|
}>;
|
|
76
76
|
getIssuerMetadata(issuerId: string): Promise<{
|
|
77
|
-
originalDraftVersion: _openid4vc_openid4vci0.
|
|
77
|
+
originalDraftVersion: _openid4vc_openid4vci0.Openid4vciVersion;
|
|
78
78
|
credentialIssuer: {
|
|
79
79
|
credential_issuer: string;
|
|
80
80
|
credential_endpoint: string;
|
|
@@ -11,7 +11,8 @@ import { OpenId4VcIssuerModuleConfig } from "./OpenId4VcIssuerModuleConfig.mjs";
|
|
|
11
11
|
import "../index.mjs";
|
|
12
12
|
import { AgentContext, Jwt, Query, QueryOptions, W3cCredentialService, W3cV2CredentialService } from "@credo-ts/core";
|
|
13
13
|
import { Jwk, Oauth2AuthorizationServer, Oauth2Client, Oauth2ResourceServer, PkceCodeChallengeMethod } from "@openid4vc/oauth2";
|
|
14
|
-
import
|
|
14
|
+
import * as _openid4vc_openid4vci2 from "@openid4vc/openid4vci";
|
|
15
|
+
import { CredentialResponse, DeferredCredentialResponse, Openid4vciIssuer } from "@openid4vc/openid4vci";
|
|
15
16
|
|
|
16
17
|
//#region src/openid4vc-issuer/OpenId4VcIssuerService.d.ts
|
|
17
18
|
/**
|
|
@@ -62,7 +63,7 @@ declare class OpenId4VcIssuerService {
|
|
|
62
63
|
* @param fetchExternalAuthorizationServerMetadata defaults to false
|
|
63
64
|
*/
|
|
64
65
|
getIssuerMetadata(agentContext: AgentContext, issuerRecord: OpenId4VcIssuerRecord, fetchExternalAuthorizationServerMetadata?: boolean): Promise<{
|
|
65
|
-
originalDraftVersion:
|
|
66
|
+
originalDraftVersion: _openid4vc_openid4vci2.Openid4vciVersion;
|
|
66
67
|
credentialIssuer: {
|
|
67
68
|
credential_issuer: string;
|
|
68
69
|
credential_endpoint: string;
|
|
@@ -136,7 +137,7 @@ declare class OpenId4VcIssuerService {
|
|
|
136
137
|
jwk: Jwk;
|
|
137
138
|
};
|
|
138
139
|
}): Promise<string>;
|
|
139
|
-
parseRefreshToken(token: string): {
|
|
140
|
+
parseRefreshToken(agentContext: AgentContext, token: string): {
|
|
140
141
|
jwt: Jwt;
|
|
141
142
|
expiresAt: Date;
|
|
142
143
|
issuerState: string | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OpenId4VcIssuerService.d.mts","names":[],"sources":["../../src/openid4vc-issuer/OpenId4VcIssuerService.ts"],"sourcesContent":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"OpenId4VcIssuerService.d.mts","names":[],"sources":["../../src/openid4vc-issuer/OpenId4VcIssuerService.ts"],"sourcesContent":[],"mappings":"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"}
|
|
@@ -609,7 +609,7 @@ let OpenId4VcIssuerService = class OpenId4VcIssuerService$1 {
|
|
|
609
609
|
const jwsService = agentContext.dependencyManager.resolve(JwsService);
|
|
610
610
|
const key = issuer.resolvedAccessTokenPublicJwk;
|
|
611
611
|
const jwt = Jwt.fromSerializedJwt(cNonce);
|
|
612
|
-
jwt.payload.validate();
|
|
612
|
+
jwt.payload.validate({ skewSeconds: agentContext.config.validitySkewSeconds });
|
|
613
613
|
if (jwt.payload.iss !== issuerMetadata.credentialIssuer.credential_issuer) throw new CredoError(`Invalid 'iss' claim in cNonce jwt`);
|
|
614
614
|
if (jwt.header.typ !== "credo+cnonce") throw new CredoError(`Invalid 'typ' claim in cNonce jwt header`);
|
|
615
615
|
if (!(await jwsService.verifyJws(agentContext, {
|
|
@@ -647,9 +647,9 @@ let OpenId4VcIssuerService = class OpenId4VcIssuerService$1 {
|
|
|
647
647
|
}
|
|
648
648
|
});
|
|
649
649
|
}
|
|
650
|
-
parseRefreshToken(token) {
|
|
650
|
+
parseRefreshToken(agentContext, token) {
|
|
651
651
|
const jwt = Jwt.fromSerializedJwt(token);
|
|
652
|
-
jwt.payload.validate();
|
|
652
|
+
jwt.payload.validate({ skewSeconds: agentContext.config.validitySkewSeconds });
|
|
653
653
|
if (!jwt.payload.exp) throw new CredoError(`Missing 'exp' claim in refresh token jwt`);
|
|
654
654
|
if (jwt.header.typ !== "credo+refresh_token") throw new CredoError(`Invalid 'typ' claim in refresh token jwt header`);
|
|
655
655
|
const { "pre-authorized_code": preAuthorizedCode, issuer_state: issuerState, cnf } = jwt.payload.additionalClaims;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OpenId4VcIssuerService.mjs","names":["OpenId4VcIssuerService","verification: OpenId4VciCredentialRequestToCredentialMapperOptions['verification']","credentialResponse: CredentialResponse","deferredCredentialResponse: DeferredCredentialResponse","firstNonce: string | undefined","proofSigners: Array<(JwtSignerWithJwk & { method: 'did' }) | JwtSignerJwk>","extraAuthorizationServers: AuthorizationServerMetadata[]","jwkThumbprint: string | undefined","grants: Parameters<Openid4vciIssuer['createCredentialOffer']>[0]['grants']","credentialConfigurationId","credentialConfiguration"],"sources":["../../src/openid4vc-issuer/OpenId4VcIssuerService.ts"],"sourcesContent":["import {\n AgentContext,\n ClaimFormat,\n CredoError,\n EventEmitter,\n injectable,\n JwsService,\n Jwt,\n JwtPayload,\n joinUriParts,\n Kms,\n MdocApi,\n type Query,\n type QueryOptions,\n SdJwtVcApi,\n TypedArrayEncoder,\n utils,\n W3cCredentialService,\n W3cV2CredentialService,\n} from '@credo-ts/core'\nimport {\n type AuthorizationServerMetadata,\n authorizationCodeGrantIdentifier,\n calculateJwkThumbprint,\n HashAlgorithm,\n type Jwk,\n type JwtSignerJwk,\n type JwtSignerWithJwk,\n Oauth2AuthorizationServer,\n Oauth2Client,\n Oauth2ErrorCodes,\n Oauth2ResourceServer,\n Oauth2ServerErrorResponseError,\n PkceCodeChallengeMethod,\n preAuthorizedCodeGrantIdentifier,\n} from '@openid4vc/oauth2'\nimport {\n type CredentialConfigurationSupportedWithFormats,\n type CredentialConfigurationsSupportedWithFormats,\n type CredentialIssuerMetadata,\n type CredentialRequestFormatSpecific,\n type CredentialResponse,\n type DeferredCredentialResponse,\n extractScopesForCredentialConfigurationIds,\n getCredentialConfigurationsMatchingRequestFormat,\n Openid4vciDraftVersion,\n Openid4vciIssuer,\n type ParseCredentialRequestReturn,\n} from '@openid4vc/openid4vci'\nimport { OpenId4VcVerifierApi } from '../openid4vc-verifier'\nimport type {\n OpenId4VciCredentialConfigurationSupportedWithFormats,\n OpenId4VciCredentialIssuerMetadata,\n OpenId4VciCredentialOfferPayload,\n OpenId4VciMetadata,\n OpenId4VcJwtIssuer,\n VerifiedOpenId4VcCredentialHolderBinding,\n} from '../shared'\nimport { OpenId4VciCredentialFormatProfile } from '../shared'\nimport { dynamicOid4vciClientAuthentication, getOid4vcCallbacks } from '../shared/callbacks'\nimport { getCredentialConfigurationsSupportedForScopes, getOfferedCredentials } from '../shared/issuerMetadataUtils'\nimport { storeActorIdForContextCorrelationId } from '../shared/router'\nimport {\n credoJwtIssuerToOpenId4VcJwtIssuer,\n decodeJwtIssuer,\n encodeJwtIssuer,\n getProofTypeFromPublicJwk,\n getPublicJwkFromDid,\n getSupportedJwaSignatureAlgorithms,\n} from '../shared/utils'\nimport { OpenId4VcIssuanceSessionState } from './OpenId4VcIssuanceSessionState'\nimport { type OpenId4VcIssuanceSessionStateChangedEvent, OpenId4VcIssuerEvents } from './OpenId4VcIssuerEvents'\nimport { OpenId4VcIssuerModuleConfig } from './OpenId4VcIssuerModuleConfig'\nimport type {\n OpenId4VciAuthorizationCodeFlowConfig,\n OpenId4VciCreateCredentialOfferOptions,\n OpenId4VciCreateCredentialResponseOptions,\n OpenId4VciCreateDeferredCredentialResponseOptions,\n OpenId4VciCreateIssuerOptions,\n OpenId4VciCreateStatelessCredentialOfferOptions,\n OpenId4VciCredentialRequestAuthorization,\n OpenId4VciCredentialRequestToCredentialMapperOptions,\n OpenId4VciPreAuthorizedCodeFlowConfig,\n OpenId4VciSignCredentials,\n OpenId4VciSignW3cCredentials,\n} from './OpenId4VcIssuerServiceOptions'\nimport {\n OpenId4VcIssuanceSessionRecord,\n OpenId4VcIssuanceSessionRepository,\n OpenId4VcIssuerRecord,\n OpenId4VcIssuerRepository,\n} from './repository'\nimport { generateTxCode } from './util/txCode'\n\n/**\n * @internal\n */\n@injectable()\nexport class OpenId4VcIssuerService {\n private w3cCredentialService: W3cCredentialService\n private w3cV2CredentialService: W3cV2CredentialService\n private openId4VcIssuerConfig: OpenId4VcIssuerModuleConfig\n private openId4VcIssuerRepository: OpenId4VcIssuerRepository\n private openId4VcIssuanceSessionRepository: OpenId4VcIssuanceSessionRepository\n\n public constructor(\n w3cCredentialService: W3cCredentialService,\n w3cV2CredentialService: W3cV2CredentialService,\n openId4VcIssuerConfig: OpenId4VcIssuerModuleConfig,\n openId4VcIssuerRepository: OpenId4VcIssuerRepository,\n openId4VcIssuanceSessionRepository: OpenId4VcIssuanceSessionRepository\n ) {\n this.w3cCredentialService = w3cCredentialService\n this.w3cV2CredentialService = w3cV2CredentialService\n this.openId4VcIssuerConfig = openId4VcIssuerConfig\n this.openId4VcIssuerRepository = openId4VcIssuerRepository\n this.openId4VcIssuanceSessionRepository = openId4VcIssuanceSessionRepository\n }\n\n public async createStatelessCredentialOffer(\n agentContext: AgentContext,\n options: OpenId4VciCreateStatelessCredentialOfferOptions & { issuer: OpenId4VcIssuerRecord }\n ): Promise<{ credentialOffer: string; credentialOfferObject: OpenId4VciCredentialOfferPayload }> {\n const { authorizationCodeFlowConfig, issuer, credentialConfigurationIds } = options\n const vcIssuer = this.getIssuer(agentContext)\n const issuerMetadata = await this.getIssuerMetadata(agentContext, issuer)\n\n const uniqueOfferedCredentials = Array.from(new Set(options.credentialConfigurationIds))\n if (uniqueOfferedCredentials.length !== credentialConfigurationIds.length) {\n throw new CredoError('All offered credentials must have unique ids.')\n }\n\n // Check if all the offered credential configuration ids have a scope value. If not, it won't be possible to actually request\n // issuance of the credential later on\n extractScopesForCredentialConfigurationIds({\n credentialConfigurationIds: options.credentialConfigurationIds,\n issuerMetadata,\n throwOnConfigurationWithoutScope: true,\n })\n\n if (authorizationCodeFlowConfig.authorizationServerUrl === issuerMetadata.credentialIssuer.credential_issuer) {\n throw new CredoError(\n 'Stateless offers can only be created for external authorization servers. Make sure to configure an external authorization server on the issuer record, and provide the authoriation server url.'\n )\n }\n\n const { credentialOffer, credentialOfferObject } = await vcIssuer.createCredentialOffer({\n credentialConfigurationIds: options.credentialConfigurationIds,\n grants: {\n authorization_code: {\n authorization_server: authorizationCodeFlowConfig.authorizationServerUrl,\n },\n },\n credentialOfferScheme: options.baseUri,\n issuerMetadata,\n })\n\n return {\n credentialOffer,\n credentialOfferObject,\n }\n }\n\n public async createCredentialOffer(\n agentContext: AgentContext,\n options: OpenId4VciCreateCredentialOfferOptions & { issuer: OpenId4VcIssuerRecord }\n ) {\n const {\n preAuthorizedCodeFlowConfig,\n authorizationCodeFlowConfig,\n issuer,\n credentialConfigurationIds,\n version = 'v1.draft15',\n authorization,\n } = options\n if (!preAuthorizedCodeFlowConfig && !authorizationCodeFlowConfig) {\n throw new CredoError('Authorization Config or Pre-Authorized Config must be provided.')\n }\n\n const vcIssuer = this.getIssuer(agentContext)\n const issuerMetadata = await this.getIssuerMetadata(agentContext, issuer)\n\n const uniqueOfferedCredentials = Array.from(new Set(options.credentialConfigurationIds))\n if (uniqueOfferedCredentials.length !== credentialConfigurationIds.length) {\n throw new CredoError('All offered credentials must have unique ids.')\n }\n\n if (uniqueOfferedCredentials.length === 0) {\n throw new CredoError('You need to offer at least one credential.')\n }\n\n // We always use shortened URIs currently\n const credentialOfferId = utils.uuid()\n const hostedCredentialOfferUri = joinUriParts(issuerMetadata.credentialIssuer.credential_issuer, [\n this.openId4VcIssuerConfig.credentialOfferEndpointPath,\n credentialOfferId,\n ])\n\n // Check if all the offered credential configuration ids have a scope value. If not, it won't be possible to actually request\n // issuance of the credential later on. For pre-auth it's not needed to add a scope.\n if (options.authorizationCodeFlowConfig) {\n extractScopesForCredentialConfigurationIds({\n credentialConfigurationIds: options.credentialConfigurationIds,\n issuerMetadata,\n throwOnConfigurationWithoutScope: true,\n })\n }\n\n const grants = await this.getGrantsFromConfig(agentContext, {\n issuer,\n issuerMetadata,\n preAuthorizedCodeFlowConfig,\n authorizationCodeFlowConfig,\n })\n\n const { credentialOffer, credentialOfferObject } = await vcIssuer.createCredentialOffer({\n credentialConfigurationIds: options.credentialConfigurationIds,\n grants,\n credentialOfferUri: hostedCredentialOfferUri,\n credentialOfferScheme: options.baseUri,\n issuerMetadata: {\n ...issuerMetadata,\n originalDraftVersion:\n version === 'v1.draft11-14' ? Openid4vciDraftVersion.Draft11 : Openid4vciDraftVersion.Draft15,\n },\n })\n\n const createdAt = new Date()\n const expiresAt = utils.addSecondsToDate(\n createdAt,\n this.openId4VcIssuerConfig.statefulCredentialOfferExpirationInSeconds\n )\n\n const chainedAuthorizationServerConfig = issuer.chainedAuthorizationServerConfigs?.find(\n (config) => config.issuer === authorizationCodeFlowConfig?.authorizationServerUrl\n )\n\n const issuanceSessionRepository = this.openId4VcIssuanceSessionRepository\n const issuanceSession = new OpenId4VcIssuanceSessionRecord({\n createdAt,\n expiresAt,\n credentialOfferPayload: credentialOfferObject,\n credentialOfferUri: hostedCredentialOfferUri,\n credentialOfferId,\n issuerId: issuer.issuerId,\n state: OpenId4VcIssuanceSessionState.OfferCreated,\n authorization: credentialOfferObject.grants?.authorization_code?.issuer_state\n ? {\n issuerState: credentialOfferObject.grants?.authorization_code?.issuer_state,\n }\n : undefined,\n presentation: authorizationCodeFlowConfig?.requirePresentationDuringIssuance\n ? {\n required: true,\n }\n : undefined,\n dpop: authorization?.requireDpop\n ? {\n required: true,\n }\n : undefined,\n walletAttestation: authorization?.requireWalletAttestation\n ? {\n required: true,\n }\n : undefined,\n chainedIdentity: chainedAuthorizationServerConfig\n ? {\n externalAuthorizationServerUrl: chainedAuthorizationServerConfig.issuer,\n }\n : undefined,\n // TODO: how to mix pre-auth and auth? Need to do state checks\n preAuthorizedCode: credentialOfferObject.grants?.[preAuthorizedCodeGrantIdentifier]?.['pre-authorized_code'],\n userPin: preAuthorizedCodeFlowConfig?.txCode\n ? generateTxCode(agentContext, preAuthorizedCodeFlowConfig.txCode)\n : undefined,\n generateRefreshTokens: options.generateRefreshTokens,\n issuanceMetadata: options.issuanceMetadata,\n openId4VciVersion: version,\n })\n await issuanceSessionRepository.save(agentContext, issuanceSession)\n this.emitStateChangedEvent(agentContext, issuanceSession, null)\n\n return {\n issuanceSession,\n credentialOffer,\n }\n }\n\n public async createCredentialResponse(\n agentContext: AgentContext,\n options: OpenId4VciCreateCredentialResponseOptions & { issuanceSession: OpenId4VcIssuanceSessionRecord }\n ): Promise<{ issuanceSession: OpenId4VcIssuanceSessionRecord; credentialResponse: CredentialResponse }> {\n options.issuanceSession.assertState([\n // OfferUriRetrieved is valid when doing auth flow (we should add a check)\n OpenId4VcIssuanceSessionState.OfferUriRetrieved,\n OpenId4VcIssuanceSessionState.AccessTokenCreated,\n OpenId4VcIssuanceSessionState.CredentialRequestReceived,\n // It is possible to issue multiple credentials in one session\n OpenId4VcIssuanceSessionState.CredentialsPartiallyIssued,\n ])\n const { issuanceSession } = options\n const issuer = await this.getIssuerByIssuerId(agentContext, options.issuanceSession.issuerId)\n const vcIssuer = this.getIssuer(agentContext, { issuanceSessionId: issuanceSession.id })\n const issuerMetadata = await this.getIssuerMetadata(agentContext, issuer)\n\n const parsedCredentialRequest = vcIssuer.parseCredentialRequest({\n issuerMetadata,\n credentialRequest: options.credentialRequest,\n })\n const {\n credentialRequest,\n credentialIdentifier,\n\n format,\n } = parsedCredentialRequest\n\n if (credentialIdentifier) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidCredentialRequest,\n error_description: `Using unsupported 'credential_identifier'`,\n })\n }\n\n if (credentialRequest.format && !format && !parsedCredentialRequest.credentialConfigurationId) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.UnsupportedCredentialFormat,\n error_description: `Unsupported credential request based on format '${credentialRequest.format}'`,\n })\n }\n\n if (parsedCredentialRequest.credentialConfigurationId && !parsedCredentialRequest.credentialConfiguration) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.UnsupportedCredentialFormat,\n error_description: `Unsupported credential request based on credential configuration id ${credentialRequest.credential_configuration_id}`,\n })\n }\n\n const { credentialConfiguration, credentialConfigurationId } = this.getCredentialConfigurationsForRequest({\n issuanceSession,\n issuerMetadata,\n requestFormat: format,\n credentialConfigurations:\n parsedCredentialRequest.credentialConfiguration && parsedCredentialRequest.credentialConfigurationId\n ? {\n [parsedCredentialRequest.credentialConfigurationId]: parsedCredentialRequest.credentialConfiguration,\n }\n : undefined,\n authorization: options.authorization,\n })\n\n const verifiedCredentialRequestProofs = await this.verifyCredentialRequestProofs(agentContext, {\n issuanceSession,\n issuer,\n parsedCredentialRequest,\n credentialConfiguration,\n credentialConfigurationId,\n })\n\n const mapper =\n options.credentialRequestToCredentialMapper ?? this.openId4VcIssuerConfig.credentialRequestToCredentialMapper\n\n let verification: OpenId4VciCredentialRequestToCredentialMapperOptions['verification']\n\n // NOTE: this will throw an error if the verifier module is not registered and there is a\n // verification session. But you can't get here without the verifier module anyway\n if (issuanceSession.presentation?.openId4VcVerificationSessionId) {\n const verifierApi = agentContext.dependencyManager.resolve(OpenId4VcVerifierApi)\n const session = await verifierApi.getVerificationSessionById(\n issuanceSession.presentation.openId4VcVerificationSessionId\n )\n\n const response = await verifierApi.getVerifiedAuthorizationResponse(\n issuanceSession.presentation.openId4VcVerificationSessionId\n )\n\n if (response.presentationExchange) {\n verification = {\n session,\n presentationExchange: response.presentationExchange,\n }\n } else if (response.dcql) {\n verification = {\n session,\n dcql: response.dcql,\n }\n } else {\n throw new CredoError(\n `Verified authorization response for verification session with id '${session.id}' does not have presentationExchange or dcql defined.`\n )\n }\n }\n\n const signOptionsOrDeferral = await mapper({\n agentContext,\n issuanceSession,\n holderBinding: verifiedCredentialRequestProofs,\n credentialOffer: issuanceSession.credentialOfferPayload,\n\n verification,\n\n credentialRequest: options.credentialRequest,\n credentialRequestFormat: format,\n\n // Matching credential configuration\n credentialConfiguration,\n credentialConfigurationId,\n\n // Authorization\n authorization: options.authorization,\n })\n\n let credentialResponse: CredentialResponse\n\n // NOTE: nonce in credential response is deprecated in newer drafts, but for now we keep it in\n const { cNonce, cNonceExpiresInSeconds } = await this.createNonce(agentContext, issuer)\n\n if (signOptionsOrDeferral.type === 'deferral') {\n credentialResponse = vcIssuer.createCredentialResponse({\n transactionId: signOptionsOrDeferral.transactionId,\n interval: signOptionsOrDeferral.interval,\n cNonce,\n cNonceExpiresInSeconds,\n credentialRequest: parsedCredentialRequest,\n })\n\n // Save transaction data for deferred issuance\n issuanceSession.transactions.push({\n transactionId: signOptionsOrDeferral.transactionId,\n numberOfCredentials: verifiedCredentialRequestProofs.keys.length,\n credentialConfigurationId,\n })\n\n // Determine new state\n const newState =\n issuanceSession.state === OpenId4VcIssuanceSessionState.CredentialsPartiallyIssued\n ? OpenId4VcIssuanceSessionState.CredentialsPartiallyIssued\n : OpenId4VcIssuanceSessionState.CredentialRequestReceived\n\n // Update expiry time to allow for re-check\n await this.updateExpiresAt(agentContext, issuanceSession, signOptionsOrDeferral.interval)\n\n // Update state\n await this.updateState(agentContext, issuanceSession, newState)\n } else {\n const credentials = await this.getSignedCredentials(agentContext, signOptionsOrDeferral, {\n issuanceSession,\n credentialConfiguration,\n expectedLength: verifiedCredentialRequestProofs.keys.length,\n })\n\n credentialResponse = vcIssuer.createCredentialResponse({\n credential: credentialRequest.proof ? credentials.credentials[0] : undefined,\n credentials: credentialRequest.proofs\n ? issuanceSession.openId4VciVersion === 'v1' || issuanceSession.openId4VciVersion === 'v1.draft15'\n ? credentials.credentials.map((c) => ({ credential: c }))\n : credentials.credentials\n : undefined,\n cNonce,\n cNonceExpiresInSeconds,\n credentialRequest: parsedCredentialRequest,\n })\n\n issuanceSession.issuedCredentials.push(credentialConfigurationId)\n const newState =\n issuanceSession.issuedCredentials.length >=\n issuanceSession.credentialOfferPayload.credential_configuration_ids.length\n ? OpenId4VcIssuanceSessionState.Completed\n : OpenId4VcIssuanceSessionState.CredentialsPartiallyIssued\n await this.updateState(agentContext, issuanceSession, newState)\n }\n\n return {\n credentialResponse,\n issuanceSession,\n }\n }\n\n public async createDeferredCredentialResponse(\n agentContext: AgentContext,\n options: OpenId4VciCreateDeferredCredentialResponseOptions & { issuanceSession: OpenId4VcIssuanceSessionRecord }\n ): Promise<{\n issuanceSession: OpenId4VcIssuanceSessionRecord\n deferredCredentialResponse: DeferredCredentialResponse\n }> {\n options.issuanceSession.assertState([\n OpenId4VcIssuanceSessionState.CredentialRequestReceived,\n OpenId4VcIssuanceSessionState.CredentialsPartiallyIssued,\n ])\n const transaction = options.issuanceSession.transactions.find(\n (tx) => tx.transactionId === options.deferredCredentialRequest.transaction_id\n )\n if (!transaction) {\n throw new CredoError('OpenId4VcIssuanceSessionRecord does not contain transaction with given transaction_id.')\n }\n\n const { issuanceSession } = options\n const issuer = await this.getIssuerByIssuerId(agentContext, options.issuanceSession.issuerId)\n const vcIssuer = this.getIssuer(agentContext, { issuanceSessionId: issuanceSession.id })\n\n const credentialConfigurationId = transaction.credentialConfigurationId\n const credentialConfiguration = issuer.credentialConfigurationsSupported[transaction.credentialConfigurationId]\n if (!credentialConfiguration) {\n throw new CredoError(\n 'Issuer does not contain credential configuration for the given credential configuration id.'\n )\n }\n\n const mapper =\n options.deferredCredentialRequestToCredentialMapper ??\n this.openId4VcIssuerConfig.deferredCredentialRequestToCredentialMapper\n if (!mapper) {\n throw new CredoError(\n 'OpenId4VcIssuerService does not have a defined deferredCredentialRequestToCredentialMapper.'\n )\n }\n\n const signOptionsOrDeferral = await mapper({\n agentContext,\n issuanceSession,\n deferredCredentialRequest: options.deferredCredentialRequest,\n authorization: options.authorization,\n })\n\n let deferredCredentialResponse: DeferredCredentialResponse\n if (signOptionsOrDeferral.type === 'deferral') {\n deferredCredentialResponse = vcIssuer.createDeferredCredentialResponse({\n interval: signOptionsOrDeferral.interval,\n transactionId: signOptionsOrDeferral.transactionId,\n })\n\n // Update expiry time to allow for re-check\n await this.updateExpiresAt(agentContext, issuanceSession, signOptionsOrDeferral.interval)\n } else {\n const credentials = await this.getSignedCredentials(agentContext, signOptionsOrDeferral, {\n issuanceSession,\n credentialConfiguration,\n expectedLength: transaction.numberOfCredentials,\n })\n\n deferredCredentialResponse = vcIssuer.createDeferredCredentialResponse({\n credentials: credentials.credentials.map((c) => ({ credential: c })),\n })\n\n issuanceSession.issuedCredentials.push(credentialConfigurationId)\n\n // Remove the transaction from the session, as it is now completed\n issuanceSession.transactions = issuanceSession.transactions?.filter(\n (tx) => tx.transactionId !== transaction.transactionId\n )\n\n // Determine new state\n const newState =\n issuanceSession.issuedCredentials.length >=\n issuanceSession.credentialOfferPayload.credential_configuration_ids.length\n ? OpenId4VcIssuanceSessionState.Completed\n : OpenId4VcIssuanceSessionState.CredentialsPartiallyIssued\n\n await this.updateState(agentContext, issuanceSession, newState)\n }\n\n return {\n deferredCredentialResponse,\n issuanceSession,\n }\n }\n\n private async verifyCredentialRequestProofs(\n agentContext: AgentContext,\n options: {\n parsedCredentialRequest: ParseCredentialRequestReturn\n issuer: OpenId4VcIssuerRecord\n issuanceSession: OpenId4VcIssuanceSessionRecord\n credentialConfigurationId: string\n credentialConfiguration: CredentialConfigurationSupportedWithFormats\n }\n ): Promise<VerifiedOpenId4VcCredentialHolderBinding> {\n const { parsedCredentialRequest, issuer, issuanceSession, credentialConfiguration, credentialConfigurationId } =\n options\n const { proofs } = parsedCredentialRequest\n\n const vcIssuer = this.getIssuer(agentContext, { issuanceSessionId: issuanceSession.id })\n const issuerMetadata = await this.getIssuerMetadata(agentContext, issuer)\n\n const allowedProofTypes = credentialConfiguration.proof_types_supported ?? {\n jwt: { proof_signing_alg_values_supported: getSupportedJwaSignatureAlgorithms(agentContext) },\n }\n\n const [proofType, proofValue] = (Object.entries(proofs ?? {})[0] as [string, string[]] | undefined) ?? []\n if (!proofType || !proofValue || proofValue.length === 0) {\n const { cNonce, cNonceExpiresInSeconds } = await this.createNonce(agentContext, issuer)\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description: 'Missing required proof(s) in credential request',\n c_nonce: cNonce,\n c_nonce_expires_in: cNonceExpiresInSeconds,\n })\n }\n\n if (proofType !== 'jwt' && proofType !== 'attestation') {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description: `Proof type '${proofType}' is not supported `,\n })\n }\n\n const supportedProofType = allowedProofTypes[proofType]\n if (!supportedProofType) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description: `Proof type '${proofType}' is not supported for credential configuration '${credentialConfigurationId}'`,\n })\n }\n\n if (proofType === 'attestation' && proofValue.length !== 1) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description: \"Only a single proofs entry is supported for proof type 'attestation'\",\n })\n }\n\n await this.updateState(agentContext, issuanceSession, OpenId4VcIssuanceSessionState.CredentialRequestReceived)\n\n if (proofType === 'attestation') {\n const keyAttestationJwt = proofValue[0]\n const keyAttestation = await vcIssuer.verifyCredentialRequestAttestationProof({\n issuerMetadata,\n keyAttestationJwt,\n })\n\n if (!supportedProofType.proof_signing_alg_values_supported.includes(keyAttestation.header.alg)) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description: `Proof signing alg value '${keyAttestation.header.alg}' is not supported for proof type 'attestation' in credential configuration '${credentialConfigurationId}'`,\n })\n }\n\n if (!keyAttestation.payload.nonce) {\n const { cNonce, cNonceExpiresInSeconds } = await this.createNonce(agentContext, issuer)\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description:\n 'Missing nonce in attestation proof in credential request. If no nonce is present in the attestation, use the jwt proof type instead',\n c_nonce: cNonce,\n c_nonce_expires_in: cNonceExpiresInSeconds,\n })\n }\n\n if (supportedProofType.key_attestations_required && keyAttestation) {\n const expectedKeyStorage = supportedProofType.key_attestations_required.key_storage\n const expectedUserAuthentication = supportedProofType.key_attestations_required.user_authentication\n\n if (\n expectedKeyStorage &&\n !expectedKeyStorage.some((keyStorage) => keyAttestation.payload.key_storage?.includes(keyStorage))\n ) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description: `Insufficient key_storage for key attestation. Proof type 'attestation' for credential configuration '${credentialConfigurationId}', expects one of key_storage values ${expectedKeyStorage.join(', ')}`,\n })\n }\n\n if (\n expectedUserAuthentication &&\n !expectedUserAuthentication.some((userAuthentication) =>\n keyAttestation.payload.user_authentication?.includes(userAuthentication)\n )\n ) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description: `Insufficient user_authentication for key attestation. Proof type 'attestation' for credential configuration '${credentialConfigurationId}', expects one of user_authentication values ${expectedUserAuthentication.join(', ')}`,\n })\n }\n }\n\n await this.verifyNonce(agentContext, issuer, keyAttestation.payload.nonce).catch(async (error) => {\n const { cNonce, cNonceExpiresInSeconds } = await this.createNonce(agentContext, issuer)\n throw new Oauth2ServerErrorResponseError(\n {\n error: Oauth2ErrorCodes.InvalidNonce,\n error_description: 'Invalid nonce in credential request',\n c_nonce: cNonce,\n c_nonce_expires_in: cNonceExpiresInSeconds,\n },\n {\n cause: error,\n }\n )\n })\n\n return {\n bindingMethod: 'jwk',\n keys: keyAttestation.payload.attested_keys.map((attestedKey) => {\n return {\n method: 'jwk',\n jwk: Kms.PublicJwk.fromUnknown(attestedKey),\n }\n }),\n proofType: 'attestation',\n\n // It's up to the credential request mapper to ensure we trust the key attestation signer\n // For x5c it's kinda covered already.\n keyAttestation,\n }\n }\n\n if (proofType === 'jwt') {\n let firstNonce: string | undefined\n const proofSigners: Array<(JwtSignerWithJwk & { method: 'did' }) | JwtSignerJwk> = []\n\n for (const jwt of proofValue) {\n const { signer, payload, header, keyAttestation } = await vcIssuer.verifyCredentialRequestJwtProof({\n issuerMetadata,\n jwt,\n clientId: options.issuanceSession.clientId,\n })\n\n // TODO: we should probably do this check before signature verification, but we then we\n // first need to decode the jwt\n if (!supportedProofType.proof_signing_alg_values_supported.includes(header.alg)) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description: `Proof signing alg value '${header.alg}' is not supported for proof type 'jwt' in credential configuration '${credentialConfigurationId}'`,\n })\n }\n\n if (signer.method !== 'jwk' && signer.method !== 'did') {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description: \"Only 'jwk' and 'did' binding methods supported for jwt proof\",\n })\n }\n\n if (proofSigners[0] && signer.method !== proofSigners[0].method) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description:\n \"All proofs must be signed using the same binding method. Found a mix of 'did' and 'jwk'\",\n })\n }\n\n if (proofSigners[0] && signer.alg !== proofSigners[0].alg) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description:\n \"All proofs must be signed using the same alg value. Found a mix of different 'alg' values.\",\n })\n }\n\n if (keyAttestation && signer.method === 'did') {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description: \"Binding method 'did' is not supported when a key attestation is provided.\",\n })\n }\n\n if (supportedProofType.key_attestations_required && !keyAttestation) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description: `Missing required key attestation. Key attestations are required for proof type 'jwt' in credential configuration '${credentialConfigurationId}'`,\n })\n }\n\n if (supportedProofType.key_attestations_required && keyAttestation) {\n const expectedKeyStorage = supportedProofType.key_attestations_required.key_storage\n const expectedUserAuthentication = supportedProofType.key_attestations_required.user_authentication\n\n if (\n expectedKeyStorage &&\n !expectedKeyStorage.some((keyStorage) => keyAttestation.payload.key_storage?.includes(keyStorage))\n ) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description: `Insufficient key_storage for key attestation. Proof type 'jwt' for credential configuration '${credentialConfigurationId}', expects one of key_storage values ${expectedKeyStorage.join(', ')}`,\n })\n }\n\n if (\n expectedUserAuthentication &&\n !expectedUserAuthentication.some((userAuthentication) =>\n keyAttestation.payload.user_authentication?.includes(userAuthentication)\n )\n ) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description: `Insufficient user_authentication for key attestation. Proof type 'jwt' for credential configuration '${credentialConfigurationId}', expects one of user_authentication values ${expectedUserAuthentication.join(', ')}`,\n })\n }\n }\n\n if (keyAttestation && proofValue.length > 1) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description:\n \"Only a single proofs entry is supported when jwt proof header contains 'key_attestation'\",\n })\n }\n\n if (!payload.nonce) {\n const { cNonce, cNonceExpiresInSeconds } = await this.createNonce(agentContext, issuer)\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description: 'Missing nonce in proof(s) in credential request',\n c_nonce: cNonce,\n c_nonce_expires_in: cNonceExpiresInSeconds,\n })\n }\n\n // Set previous nonce if not yet set (first iteration)\n if (!firstNonce) firstNonce = payload.nonce\n if (firstNonce !== payload.nonce) {\n const { cNonce, cNonceExpiresInSeconds } = await this.createNonce(agentContext, issuer)\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description: 'Not all nonce values in proofs are equal',\n c_nonce: cNonce,\n c_nonce_expires_in: cNonceExpiresInSeconds,\n })\n }\n\n // IF nonce is provided in the key attestation (not required with jwt proof) then\n // it MUST match with the nonce of the JWT proof\n if (keyAttestation?.payload.nonce && keyAttestation.payload.nonce !== payload.nonce) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description:\n 'If a nonce is present in the key attestation, the nonce in the proof jwt must be equal to the nonce in the key attestation',\n })\n }\n\n // Verify the nonce\n await this.verifyNonce(agentContext, issuer, payload.nonce).catch(async (error) => {\n const { cNonce, cNonceExpiresInSeconds } = await this.createNonce(agentContext, issuer)\n throw new Oauth2ServerErrorResponseError(\n {\n error: Oauth2ErrorCodes.InvalidNonce,\n error_description: 'Invalid nonce in credential request',\n c_nonce: cNonce,\n c_nonce_expires_in: cNonceExpiresInSeconds,\n },\n {\n cause: error,\n }\n )\n })\n\n if (keyAttestation) {\n return {\n proofType: 'jwt',\n bindingMethod: 'jwk',\n keys: keyAttestation.payload.attested_keys.map((attestedKey) => {\n return {\n method: 'jwk',\n jwk: Kms.PublicJwk.fromUnknown(attestedKey),\n }\n }),\n keyAttestation,\n }\n }\n proofSigners.push(signer)\n }\n\n if (proofSigners[0].method === 'did') {\n const signers = proofSigners as Array<JwtSignerWithJwk & { method: 'did' }>\n return {\n proofType: 'jwt',\n bindingMethod: 'did',\n keys: signers.map((signer) => ({\n didUrl: signer.didUrl,\n method: 'did',\n jwk: Kms.PublicJwk.fromUnknown(signer.publicJwk),\n })),\n }\n }\n\n return {\n proofType: 'jwt',\n bindingMethod: 'jwk',\n keys: (proofSigners as JwtSignerJwk[]).map((signer) => {\n return {\n method: 'jwk',\n jwk: Kms.PublicJwk.fromUnknown(signer.publicJwk),\n }\n }),\n }\n }\n\n // This will not happen, but to make TS happy\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description: 'Missing required proof(s) in credential request',\n })\n }\n\n public async findIssuanceSessionsByQuery(\n agentContext: AgentContext,\n query: Query<OpenId4VcIssuanceSessionRecord>,\n queryOptions?: QueryOptions\n ) {\n return this.openId4VcIssuanceSessionRepository.findByQuery(agentContext, query, queryOptions)\n }\n\n public async findSingleIssuanceSessionByQuery(\n agentContext: AgentContext,\n query: Query<OpenId4VcIssuanceSessionRecord>\n ) {\n return this.openId4VcIssuanceSessionRepository.findSingleByQuery(agentContext, query)\n }\n\n public async getIssuanceSessionById(agentContext: AgentContext, issuanceSessionId: string) {\n return this.openId4VcIssuanceSessionRepository.getById(agentContext, issuanceSessionId)\n }\n\n public async getAllIssuers(agentContext: AgentContext) {\n return this.openId4VcIssuerRepository.getAll(agentContext)\n }\n\n public async getIssuerByIssuerId(agentContext: AgentContext, issuerId: string) {\n return this.openId4VcIssuerRepository.getByIssuerId(agentContext, issuerId)\n }\n\n public async updateIssuer(agentContext: AgentContext, issuer: OpenId4VcIssuerRecord) {\n if (issuer.signedMetadata) {\n const issuerMetadata = await this.getIssuerMetadata(agentContext, issuer, false)\n issuer.signedMetadata = await this.createSignedMetadata(\n agentContext,\n issuerMetadata.credentialIssuer,\n decodeJwtIssuer(issuer.signedMetadata.signer)\n )\n }\n\n await this.openId4VcIssuerRepository.update(agentContext, issuer)\n }\n\n public async createIssuer(agentContext: AgentContext, options: OpenId4VciCreateIssuerOptions) {\n const kms = agentContext.resolve(Kms.KeyManagementApi)\n\n // TODO: ideally we can store additional data with a key, such as:\n // - createdAt\n // - purpose\n const accessTokenSignerKey = await kms.createKey({\n type: options.accessTokenSignerKeyType ?? { kty: 'OKP', crv: 'Ed25519' },\n })\n\n const openId4VcIssuer = new OpenId4VcIssuerRecord({\n issuerId: options.issuerId ?? utils.uuid(),\n display: options.display,\n dpopSigningAlgValuesSupported: options.dpopSigningAlgValuesSupported,\n accessTokenPublicJwk: accessTokenSignerKey.publicJwk,\n authorizationServerConfigs: options.authorizationServerConfigs,\n credentialConfigurationsSupported: options.credentialConfigurationsSupported,\n batchCredentialIssuance: options.batchCredentialIssuance,\n })\n\n if (options.metadataSigner) {\n const issuerMetadata = await this.getIssuerMetadata(agentContext, openId4VcIssuer, false)\n openId4VcIssuer.signedMetadata = await this.createSignedMetadata(\n agentContext,\n issuerMetadata.credentialIssuer,\n options.metadataSigner\n )\n }\n\n await this.openId4VcIssuerRepository.save(agentContext, openId4VcIssuer)\n await storeActorIdForContextCorrelationId(agentContext, openId4VcIssuer.issuerId)\n return openId4VcIssuer\n }\n\n private async createSignedMetadata(\n agentContext: AgentContext,\n credentialIssuerMetadata: OpenId4VciCredentialIssuerMetadata,\n metadataSigner: OpenId4VcJwtIssuer\n ) {\n const issuer = this.getIssuer(agentContext)\n const credentialIssuerMetadataJwt = await issuer.createSignedCredentialIssuerMetadataJwt({\n credentialIssuerMetadata,\n signer: await credoJwtIssuerToOpenId4VcJwtIssuer(agentContext, metadataSigner),\n })\n\n return {\n jwt: credentialIssuerMetadataJwt,\n signer: encodeJwtIssuer(metadataSigner),\n }\n }\n\n public async rotateAccessTokenSigningKey(\n agentContext: AgentContext,\n issuer: OpenId4VcIssuerRecord,\n options?: Pick<OpenId4VciCreateIssuerOptions, 'accessTokenSignerKeyType'>\n ) {\n const kms = agentContext.resolve(Kms.KeyManagementApi)\n\n const previousKey = issuer.resolvedAccessTokenPublicJwk\n const accessTokenSignerKey = await kms.createKey({\n type: options?.accessTokenSignerKeyType ?? { kty: 'OKP', crv: 'Ed25519' },\n })\n\n issuer.accessTokenPublicJwk = accessTokenSignerKey.publicJwk\n await this.openId4VcIssuerRepository.update(agentContext, issuer)\n\n // Remove previous key\n await kms.deleteKey({\n keyId: previousKey.keyId,\n })\n }\n\n /**\n * @param fetchExternalAuthorizationServerMetadata defaults to false\n */\n public async getIssuerMetadata(\n agentContext: AgentContext,\n issuerRecord: OpenId4VcIssuerRecord,\n fetchExternalAuthorizationServerMetadata = false\n ) {\n const config = agentContext.dependencyManager.resolve(OpenId4VcIssuerModuleConfig)\n const issuerUrl = joinUriParts(config.baseUrl, [issuerRecord.issuerId])\n const oauth2Client = this.getOauth2Client(agentContext)\n const directAuthorizationServerConfigs = issuerRecord.directAuthorizationServerConfigs\n\n const extraAuthorizationServers: AuthorizationServerMetadata[] =\n fetchExternalAuthorizationServerMetadata && directAuthorizationServerConfigs\n ? await Promise.all(\n directAuthorizationServerConfigs.map(async (server) => {\n const metadata = await oauth2Client.fetchAuthorizationServerMetadata(server.issuer)\n if (!metadata)\n throw new CredoError(`Authorization server metadata not found for issuer '${server.issuer}'`)\n return metadata\n })\n )\n : []\n\n const authorizationServers =\n directAuthorizationServerConfigs && directAuthorizationServerConfigs.length > 0\n ? [\n ...directAuthorizationServerConfigs.map((authorizationServer) => authorizationServer.issuer),\n // Our issuer is also a valid authorization server (for pre-auth and chained auth)\n issuerUrl,\n ]\n : undefined\n\n const credentialIssuerMetadata = {\n credential_issuer: issuerUrl,\n credential_endpoint: joinUriParts(issuerUrl, [config.credentialEndpointPath]),\n deferred_credential_endpoint: joinUriParts(issuerUrl, [config.deferredCredentialEndpointPath]),\n credential_configurations_supported: issuerRecord.credentialConfigurationsSupported ?? {},\n authorization_servers: authorizationServers,\n display: issuerRecord.display,\n nonce_endpoint: joinUriParts(issuerUrl, [config.nonceEndpointPath]),\n batch_credential_issuance: issuerRecord.batchCredentialIssuance\n ? {\n batch_size: issuerRecord.batchCredentialIssuance.batchSize,\n }\n : undefined,\n } satisfies CredentialIssuerMetadata\n\n const issuerAuthorizationServer = {\n issuer: issuerUrl,\n token_endpoint: joinUriParts(issuerUrl, [config.accessTokenEndpointPath]),\n 'pre-authorized_grant_anonymous_access_supported': true,\n\n jwks_uri: joinUriParts(issuerUrl, [config.jwksEndpointPath]),\n\n grant_types_supported: [authorizationCodeGrantIdentifier, preAuthorizedCodeGrantIdentifier],\n\n authorization_challenge_endpoint: joinUriParts(issuerUrl, [config.authorizationChallengeEndpointPath]),\n authorization_endpoint: joinUriParts(issuerUrl, [config.authorizationEndpoint]),\n\n pushed_authorization_request_endpoint: joinUriParts(issuerUrl, [config.pushedAuthorizationRequestEndpoint]),\n require_pushed_authorization_requests: true,\n\n code_challenge_methods_supported: [PkceCodeChallengeMethod.S256],\n dpop_signing_alg_values_supported: issuerRecord.dpopSigningAlgValuesSupported,\n } satisfies AuthorizationServerMetadata\n\n return {\n originalDraftVersion: Openid4vciDraftVersion.V1,\n credentialIssuer: credentialIssuerMetadata,\n authorizationServers: [issuerAuthorizationServer, ...extraAuthorizationServers],\n knownCredentialConfigurations: credentialIssuerMetadata.credential_configurations_supported,\n\n signedMetadataJwt: issuerRecord.signedMetadata?.jwt,\n }\n }\n\n public async createNonce(agentContext: AgentContext, issuer: OpenId4VcIssuerRecord) {\n const issuerMetadata = await this.getIssuerMetadata(agentContext, issuer)\n const jwsService = agentContext.dependencyManager.resolve(JwsService)\n\n const cNonceExpiresInSeconds = this.openId4VcIssuerConfig.cNonceExpiresInSeconds\n const cNonceExpiresAt = utils.addSecondsToDate(new Date(), cNonceExpiresInSeconds)\n\n const key = issuer.resolvedAccessTokenPublicJwk\n const cNonce = await jwsService.createJwsCompact(agentContext, {\n keyId: key.keyId,\n payload: JwtPayload.fromJson({\n iss: issuerMetadata.credentialIssuer.credential_issuer,\n exp: utils.dateToSeconds(cNonceExpiresAt),\n }),\n protectedHeaderOptions: {\n typ: 'credo+cnonce',\n kid: key.keyId,\n alg: key.signatureAlgorithm,\n },\n })\n\n return {\n cNonce,\n cNonceExpiresAt,\n cNonceExpiresInSeconds,\n }\n }\n\n /**\n * @todo nonces are very short lived (1 min), but it might be nice to also cache the nonces\n * in the cache if we have 'seen' them. They will only be in the cache for a short time\n * and it will prevent replay\n */\n private async verifyNonce(agentContext: AgentContext, issuer: OpenId4VcIssuerRecord, cNonce: string) {\n const issuerMetadata = await this.getIssuerMetadata(agentContext, issuer)\n const jwsService = agentContext.dependencyManager.resolve(JwsService)\n\n const key = issuer.resolvedAccessTokenPublicJwk\n const jwt = Jwt.fromSerializedJwt(cNonce)\n jwt.payload.validate()\n\n if (jwt.payload.iss !== issuerMetadata.credentialIssuer.credential_issuer) {\n throw new CredoError(`Invalid 'iss' claim in cNonce jwt`)\n }\n if (jwt.header.typ !== 'credo+cnonce') {\n throw new CredoError(`Invalid 'typ' claim in cNonce jwt header`)\n }\n\n const verification = await jwsService.verifyJws(agentContext, {\n jws: cNonce,\n jwsSigner: {\n method: 'jwk',\n jwk: key,\n },\n })\n\n if (!verification.isValid) {\n throw new CredoError('Invalid nonce')\n }\n }\n\n public async createRefreshToken(\n agentContext: AgentContext,\n issuer: OpenId4VcIssuerRecord,\n options: {\n issuerState?: string\n preAuthorizedCode?: string\n dpop?: {\n jwk: Jwk\n }\n }\n ) {\n const issuerMetadata = await this.getIssuerMetadata(agentContext, issuer)\n const jwsService = agentContext.dependencyManager.resolve(JwsService)\n\n const expiresInSeconds = this.openId4VcIssuerConfig.refreshTokenExpiresInSeconds\n const expiresAt = utils.addSecondsToDate(new Date(), expiresInSeconds)\n\n const key = issuer.resolvedAccessTokenPublicJwk\n const refreshToken = await jwsService.createJwsCompact(agentContext, {\n keyId: key.keyId,\n payload: JwtPayload.fromJson({\n iss: issuerMetadata.credentialIssuer.credential_issuer,\n aud: issuerMetadata.credentialIssuer.credential_issuer,\n exp: utils.dateToSeconds(expiresAt),\n issuer_state: options.issuerState,\n 'pre-authorized_code': options.preAuthorizedCode,\n cnf: options.dpop\n ? {\n jkt: await calculateJwkThumbprint({\n hashAlgorithm: HashAlgorithm.Sha256,\n hashCallback: getOid4vcCallbacks(agentContext).hash,\n jwk: options.dpop.jwk,\n }),\n }\n : undefined,\n }),\n protectedHeaderOptions: {\n typ: 'credo+refresh_token',\n kid: key.keyId,\n alg: key.signatureAlgorithm,\n },\n })\n\n return refreshToken\n }\n\n public parseRefreshToken(token: string) {\n const jwt = Jwt.fromSerializedJwt(token)\n jwt.payload.validate()\n\n if (!jwt.payload.exp) {\n throw new CredoError(`Missing 'exp' claim in refresh token jwt`)\n }\n if (jwt.header.typ !== 'credo+refresh_token') {\n throw new CredoError(`Invalid 'typ' claim in refresh token jwt header`)\n }\n\n const { 'pre-authorized_code': preAuthorizedCode, issuer_state: issuerState, cnf } = jwt.payload.additionalClaims\n\n if (preAuthorizedCode && typeof preAuthorizedCode !== 'string') {\n throw new CredoError(`Invalid 'pre-authorized_code' claim in refresh token jwt payload`)\n }\n\n if (issuerState && typeof issuerState !== 'string') {\n throw new CredoError(`Invalid 'issuer_state' claim in refresh token jwt payload`)\n }\n\n if (!preAuthorizedCode && !issuerState) {\n throw new CredoError(`Missing 'issuer_state' or 'pre-authorized_code' claim in refresh token jwt payload`)\n }\n\n let jwkThumbprint: string | undefined\n if (cnf) {\n if (typeof cnf !== 'object' || !('jkt' in cnf) || typeof cnf.jkt !== 'string') {\n throw new CredoError(`Invalid 'cnf' claim in refresh token jwt payload`)\n }\n\n jwkThumbprint = cnf.jkt\n }\n\n return {\n jwt,\n expiresAt: new Date(jwt.payload.exp * 1000),\n issuerState: issuerState as string | undefined,\n preAuthorizedCode: preAuthorizedCode as string | undefined,\n dpop: jwkThumbprint\n ? {\n jwkThumbprint,\n }\n : undefined,\n }\n }\n\n public async verifyRefreshToken(\n agentContext: AgentContext,\n issuer: OpenId4VcIssuerRecord,\n parsedRefreshToken: ReturnType<OpenId4VcIssuerService['parseRefreshToken']>,\n options: {\n dpop?: {\n jwkThumbprint?: string\n }\n } = {}\n ) {\n const issuerMetadata = await this.getIssuerMetadata(agentContext, issuer)\n const jwsService = agentContext.dependencyManager.resolve(JwsService)\n\n const key = issuer.resolvedAccessTokenPublicJwk\n\n if (parsedRefreshToken.jwt.payload.iss !== issuerMetadata.credentialIssuer.credential_issuer) {\n throw new CredoError(`Invalid 'iss' claim in refresh token jwt`)\n }\n if (parsedRefreshToken.jwt.payload.aud !== issuerMetadata.credentialIssuer.credential_issuer) {\n throw new CredoError(`Invalid 'aud' claim in refresh token jwt`)\n }\n\n const verification = await jwsService.verifyJws(agentContext, {\n jws: parsedRefreshToken.jwt.serializedJwt,\n jwsSigner: {\n method: 'jwk',\n jwk: key,\n },\n })\n\n if (!verification.isValid) {\n throw new CredoError('Invalid refresh token')\n }\n\n if (options.dpop?.jwkThumbprint) {\n if (parsedRefreshToken.dpop?.jwkThumbprint !== options.dpop.jwkThumbprint) {\n throw new CredoError(`Invalid 'cnf.jkt' claim in refresh token jwt payload`)\n }\n }\n }\n\n public getIssuer(agentContext: AgentContext, options: { issuanceSessionId?: string } = {}) {\n return new Openid4vciIssuer({\n callbacks: getOid4vcCallbacks(agentContext, options),\n })\n }\n\n public getOauth2Client(agentContext: AgentContext, issuerRecord?: OpenId4VcIssuerRecord) {\n return new Oauth2Client({\n callbacks: {\n ...getOid4vcCallbacks(agentContext),\n ...(issuerRecord\n ? { clientAuthentication: dynamicOid4vciClientAuthentication(agentContext, issuerRecord) }\n : {}),\n },\n })\n }\n\n public getOauth2AuthorizationServer(agentContext: AgentContext, options: { issuanceSessionId?: string } = {}) {\n return new Oauth2AuthorizationServer({\n callbacks: getOid4vcCallbacks(agentContext, options),\n })\n }\n\n public getResourceServer(agentContext: AgentContext, issuerRecord: OpenId4VcIssuerRecord) {\n return new Oauth2ResourceServer({\n callbacks: {\n ...getOid4vcCallbacks(agentContext),\n clientAuthentication: dynamicOid4vciClientAuthentication(agentContext, issuerRecord),\n },\n })\n }\n\n /**\n * Update the expiresAt field of the issuance session to ensure it remains\n * valid during the deferral process. We set it to the maximum between the\n * current expiresAt and the current time plus the configured expiration\n * time or the interval multiplied by 2. This accounts for the chance of multiple\n * deferrals happening, with longer intervals.\n */\n private async updateExpiresAt(\n agentContext: AgentContext,\n issuanceSession: OpenId4VcIssuanceSessionRecord,\n interval: number\n ) {\n const expiresAt =\n issuanceSession.expiresAt ??\n utils.addSecondsToDate(\n issuanceSession.createdAt,\n this.openId4VcIssuerConfig.statefulCredentialOfferExpirationInSeconds\n )\n\n issuanceSession.expiresAt = new Date(\n Math.max(\n expiresAt.getTime(),\n utils\n .addSecondsToDate(\n new Date(),\n Math.max(this.openId4VcIssuerConfig.statefulCredentialOfferExpirationInSeconds, interval * 2)\n )\n .getTime()\n )\n )\n\n await this.openId4VcIssuanceSessionRepository.update(agentContext, issuanceSession)\n }\n\n /**\n * Update the record to a new state and emit an state changed event. Also updates the record\n * in storage.\n */\n public async updateState(\n agentContext: AgentContext,\n issuanceSession: OpenId4VcIssuanceSessionRecord,\n newState: OpenId4VcIssuanceSessionState\n ) {\n agentContext.config.logger.debug(\n `Updating openid4vc issuance session record ${issuanceSession.id} to state ${newState} (previous=${issuanceSession.state})`\n )\n\n const previousState = issuanceSession.state\n issuanceSession.state = newState\n await this.openId4VcIssuanceSessionRepository.update(agentContext, issuanceSession)\n\n this.emitStateChangedEvent(agentContext, issuanceSession, previousState)\n }\n\n public emitStateChangedEvent(\n agentContext: AgentContext,\n issuanceSession: OpenId4VcIssuanceSessionRecord,\n previousState: OpenId4VcIssuanceSessionState | null\n ) {\n const eventEmitter = agentContext.dependencyManager.resolve(EventEmitter)\n\n eventEmitter.emit<OpenId4VcIssuanceSessionStateChangedEvent>(agentContext, {\n type: OpenId4VcIssuerEvents.IssuanceSessionStateChanged,\n payload: {\n issuanceSession: issuanceSession.clone(),\n previousState: previousState,\n },\n })\n }\n\n private async getGrantsFromConfig(\n agentContext: AgentContext,\n config: {\n issuer: OpenId4VcIssuerRecord\n issuerMetadata: OpenId4VciMetadata\n preAuthorizedCodeFlowConfig?: OpenId4VciPreAuthorizedCodeFlowConfig\n authorizationCodeFlowConfig?: OpenId4VciAuthorizationCodeFlowConfig\n }\n ) {\n const kms = agentContext.resolve(Kms.KeyManagementApi)\n const { preAuthorizedCodeFlowConfig, authorizationCodeFlowConfig, issuer, issuerMetadata } = config\n\n // TODO: export type\n const grants: Parameters<Openid4vciIssuer['createCredentialOffer']>[0]['grants'] = {}\n\n // Pre auth\n if (preAuthorizedCodeFlowConfig) {\n const { txCode, authorizationServerUrl, preAuthorizedCode } = preAuthorizedCodeFlowConfig\n\n grants[preAuthorizedCodeGrantIdentifier] = {\n 'pre-authorized_code': preAuthorizedCode ?? TypedArrayEncoder.toBase64URL(kms.randomBytes({ length: 32 })),\n tx_code: txCode,\n authorization_server: config.issuerMetadata.credentialIssuer.authorization_servers\n ? authorizationServerUrl\n : undefined,\n }\n }\n\n // Auth\n if (authorizationCodeFlowConfig) {\n const { requirePresentationDuringIssuance } = authorizationCodeFlowConfig\n let authorizationServerUrl = authorizationCodeFlowConfig.authorizationServerUrl\n\n if (requirePresentationDuringIssuance) {\n if (authorizationServerUrl && authorizationServerUrl !== issuerMetadata.credentialIssuer.credential_issuer) {\n throw new CredoError(\n `When 'requirePresentationDuringIssuance' is set, 'authorizationServerUrl' must be undefined or match the credential issuer identifier`\n )\n }\n\n authorizationServerUrl = issuerMetadata.credentialIssuer.credential_issuer\n }\n\n const authorizationServerConfig = issuer.authorizationServerConfigs?.find(\n (server) => server.issuer === authorizationServerUrl\n )\n if (authorizationServerConfig?.type === 'chained') {\n authorizationServerUrl = issuerMetadata.credentialIssuer.credential_issuer\n }\n\n grants.authorization_code = {\n issuer_state:\n // TODO: the issuer_state should not be guessable, so it's best if we generate it and now allow the user to provide it?\n // but same is true for the pre-auth code and users of credo can also provide that value. We can't easily do unique constraint with askat\n authorizationCodeFlowConfig.issuerState ?? TypedArrayEncoder.toBase64URL(kms.randomBytes({ length: 32 })),\n authorization_server: config.issuerMetadata.credentialIssuer.authorization_servers\n ? authorizationServerUrl\n : undefined,\n }\n }\n\n return grants\n }\n\n private getCredentialConfigurationsForRequest(options: {\n issuerMetadata: OpenId4VciMetadata\n issuanceSession: OpenId4VcIssuanceSessionRecord\n authorization: OpenId4VciCredentialRequestAuthorization\n requestFormat?: CredentialRequestFormatSpecific\n credentialConfigurations?: CredentialConfigurationsSupportedWithFormats\n }): { credentialConfigurationId: string; credentialConfiguration: CredentialConfigurationSupportedWithFormats } {\n const { requestFormat, issuanceSession, issuerMetadata, authorization, credentialConfigurations } = options\n\n // Check against all credential configurations\n const configurationsMatchingRequest = credentialConfigurations\n ? credentialConfigurations\n : requestFormat\n ? getCredentialConfigurationsMatchingRequestFormat({\n requestFormat,\n issuerMetadata,\n })\n : undefined\n\n if (!configurationsMatchingRequest) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidCredentialRequest,\n error_description: `Either 'credential_configuration_id' or 'format' needs to be defined'`,\n })\n }\n\n if (Object.keys(configurationsMatchingRequest).length === 0) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidCredentialRequest,\n error_description: 'Credential request does not match any credential configuration',\n })\n }\n\n // Limit to offered configurations\n const configurationsMatchingRequestAndOffer = getOfferedCredentials(\n issuanceSession.credentialOfferPayload.credential_configuration_ids,\n configurationsMatchingRequest,\n { ignoreNotFoundIds: true }\n )\n if (Object.keys(configurationsMatchingRequestAndOffer).length === 0) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidCredentialRequest,\n error_description: 'Credential request does not match any credential configurations from credential offer',\n })\n }\n\n // Limit to not-issued and not-deferred configurations\n const deferredCredentialConfigurationIds = issuanceSession.transactions.map((tx) => tx.credentialConfigurationId)\n const configurationsMatchingRequestAndOfferNotIssued = getOfferedCredentials(\n issuanceSession.credentialOfferPayload.credential_configuration_ids.filter(\n (id) => !issuanceSession.issuedCredentials.includes(id) && !deferredCredentialConfigurationIds.includes(id)\n ),\n configurationsMatchingRequestAndOffer,\n { ignoreNotFoundIds: true }\n )\n if (Object.keys(configurationsMatchingRequestAndOfferNotIssued).length === 0) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidCredentialRequest,\n error_description:\n 'Credential request does not match any credential configurations from credential offer that have not been issued yet',\n })\n }\n\n // For pre-auth we allow all ids from the offer\n if (authorization.accessToken.payload['pre-authorized_code']) {\n // We return the first one that matches all checks. Pre draft 15 it could be multiple entries, but only if you offer\n // multiple credentials of the same type. We need to do checks on this, so we pick the first one\n const [credentialConfigurationId, credentialConfiguration] = Object.entries(\n configurationsMatchingRequestAndOfferNotIssued\n )[0]\n return {\n credentialConfigurationId,\n credentialConfiguration,\n }\n }\n\n // Limit to scopes from the token\n // We only do this for auth flow, so it's not required to add a scope for every configuration.\n const configurationsMatchingRequestOfferScope = getCredentialConfigurationsSupportedForScopes(\n configurationsMatchingRequestAndOfferNotIssued,\n authorization.accessToken.payload.scope?.split(' ') ?? []\n )\n if (Object.keys(configurationsMatchingRequestOfferScope).length === 0) {\n throw new Oauth2ServerErrorResponseError(\n {\n error: Oauth2ErrorCodes.InsufficientScope,\n error_description:\n 'Scope does not grant issuance for any requested credential configurations from credential offer',\n },\n {\n status: 403,\n }\n )\n }\n\n // We return the first one that matches all checks. Pre draft 15 it could be multiple entries, but only if you offer\n // multiple credentials of the same type. We need to do checks on this, so we pick the first one\n const [credentialConfigurationId, credentialConfiguration] = Object.entries(\n configurationsMatchingRequestOfferScope\n )[0]\n return {\n credentialConfigurationId,\n credentialConfiguration: credentialConfiguration as CredentialConfigurationSupportedWithFormats,\n }\n }\n\n private async getSignedCredentials(\n agentContext: AgentContext,\n signOptions: OpenId4VciSignCredentials,\n options: {\n issuanceSession: OpenId4VcIssuanceSessionRecord\n credentialConfiguration: OpenId4VciCredentialConfigurationSupportedWithFormats\n expectedLength: number\n }\n ): Promise<{\n credentials: string[] | Record<string, unknown>[]\n format: `${OpenId4VciCredentialFormatProfile}`\n }> {\n const { credentialConfiguration, expectedLength } = options\n\n // NOTE: we may want to allow a mismatch between this (as there is a match batch length), but for now it needs to match\n if (signOptions.credentials.length !== expectedLength) {\n throw new CredoError(\n `Credential request to credential mapper returned '${signOptions.credentials.length}' to be signed, while '${expectedLength}' holder binding entries were provided. Make sure to return one credential for each holder binding entry`\n )\n }\n\n if (signOptions.format === ClaimFormat.JwtVc || signOptions.format === ClaimFormat.LdpVc) {\n const oid4vciFormatMap: Record<string, ClaimFormat.JwtVc | ClaimFormat.LdpVc> = {\n [OpenId4VciCredentialFormatProfile.JwtVcJson]: ClaimFormat.JwtVc,\n [OpenId4VciCredentialFormatProfile.JwtVcJsonLd]: ClaimFormat.JwtVc,\n [OpenId4VciCredentialFormatProfile.LdpVc]: ClaimFormat.LdpVc,\n }\n\n const expectedClaimFormat = oid4vciFormatMap[credentialConfiguration.format]\n if (signOptions.format !== expectedClaimFormat) {\n throw new CredoError(\n `Invalid credential format returned by sign options. Expected '${expectedClaimFormat}', received '${signOptions.format}'.`\n )\n }\n\n return {\n format: credentialConfiguration.format,\n credentials: (await Promise.all(\n signOptions.credentials.map((credential) =>\n this.signW3cCredential(agentContext, signOptions.format, credential).then((signed) => signed.encoded)\n )\n )) as string[] | Record<string, unknown>[],\n }\n }\n if (signOptions.format === ClaimFormat.SdJwtDc) {\n if (\n credentialConfiguration.format !== OpenId4VciCredentialFormatProfile.SdJwtVc &&\n credentialConfiguration.format !== OpenId4VciCredentialFormatProfile.SdJwtDc\n ) {\n throw new CredoError(\n `Invalid credential format returned by sign options. Expected '${ClaimFormat.SdJwtDc}', received '${signOptions.format}'.`\n )\n }\n\n if (!signOptions.credentials.every((c) => c.payload.vct === credentialConfiguration.vct)) {\n throw new CredoError(\n `One or more vct values of the offered credential(s) do not match the vct of the requested credential. Offered ${Array.from(\n new Set(signOptions.credentials.map((c) => `'${c.payload.vct}'`))\n ).join(', ')} Requested '${credentialConfiguration.vct}'.`\n )\n }\n\n const sdJwtVcApi = agentContext.dependencyManager.resolve(SdJwtVcApi)\n return {\n format: credentialConfiguration.format,\n credentials: await Promise.all(\n signOptions.credentials.map((credential) =>\n sdJwtVcApi\n .sign({\n ...credential,\n // Set header type based on the oid4vci format\n headerType: credentialConfiguration.format,\n })\n .then((signed) => signed.compact)\n )\n ),\n }\n }\n if (signOptions.format === ClaimFormat.MsoMdoc) {\n if (signOptions.format !== credentialConfiguration.format) {\n throw new CredoError(\n `Invalid credential format returned by sign options. Expected '${credentialConfiguration.format}', received '${signOptions.format}'.`\n )\n }\n if (!signOptions.credentials.every((c) => c.docType === credentialConfiguration.doctype)) {\n throw new CredoError(\n `One or more doctype values of the offered credential(s) do not match the doctype of the requested credential. Offered ${Array.from(\n new Set(signOptions.credentials.map((c) => `'${c.docType}'`))\n ).join(', ')} Requested '${credentialConfiguration.doctype}'.`\n )\n }\n\n const mdocApi = agentContext.dependencyManager.resolve(MdocApi)\n return {\n format: OpenId4VciCredentialFormatProfile.MsoMdoc,\n credentials: await Promise.all(\n signOptions.credentials.map((credential) => mdocApi.sign(credential).then((signed) => signed.base64Url))\n ),\n }\n }\n if (signOptions.format === ClaimFormat.SdJwtW3cVc) {\n return {\n format: credentialConfiguration.format,\n credentials: (await Promise.all(\n signOptions.credentials.map((credential) =>\n this.w3cV2CredentialService\n .signCredential(agentContext, {\n format: ClaimFormat.SdJwtW3cVc,\n ...credential,\n })\n .then((signed) => signed.encoded)\n )\n )) as string[] | Record<string, unknown>[],\n }\n }\n throw new CredoError(`Unsupported credential format ${signOptions.format}`)\n }\n\n private async signW3cCredential(\n agentContext: AgentContext,\n format: `${ClaimFormat.JwtVc}` | `${ClaimFormat.LdpVc}`,\n options: OpenId4VciSignW3cCredentials['credentials'][number]\n ) {\n const publicJwk = await getPublicJwkFromDid(agentContext, options.verificationMethod)\n if (format === ClaimFormat.JwtVc) {\n return await this.w3cCredentialService.signCredential(agentContext, {\n format: ClaimFormat.JwtVc,\n credential: options.credential,\n verificationMethod: options.verificationMethod,\n alg: publicJwk.signatureAlgorithm,\n })\n }\n\n const proofType = getProofTypeFromPublicJwk(agentContext, publicJwk)\n return await this.w3cCredentialService.signCredential(agentContext, {\n format: ClaimFormat.LdpVc,\n credential: options.credential,\n verificationMethod: options.verificationMethod,\n proofType: proofType,\n })\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"OpenId4VcIssuerService.mjs","names":["OpenId4VcIssuerService","verification: OpenId4VciCredentialRequestToCredentialMapperOptions['verification']","credentialResponse: CredentialResponse","deferredCredentialResponse: DeferredCredentialResponse","firstNonce: string | undefined","proofSigners: Array<(JwtSignerWithJwk & { method: 'did' }) | JwtSignerJwk>","extraAuthorizationServers: AuthorizationServerMetadata[]","jwkThumbprint: string | undefined","grants: Parameters<Openid4vciIssuer['createCredentialOffer']>[0]['grants']","credentialConfigurationId","credentialConfiguration"],"sources":["../../src/openid4vc-issuer/OpenId4VcIssuerService.ts"],"sourcesContent":["import {\n AgentContext,\n ClaimFormat,\n CredoError,\n EventEmitter,\n injectable,\n JwsService,\n Jwt,\n JwtPayload,\n joinUriParts,\n Kms,\n MdocApi,\n type Query,\n type QueryOptions,\n SdJwtVcApi,\n TypedArrayEncoder,\n utils,\n W3cCredentialService,\n W3cV2CredentialService,\n} from '@credo-ts/core'\nimport {\n type AuthorizationServerMetadata,\n authorizationCodeGrantIdentifier,\n calculateJwkThumbprint,\n HashAlgorithm,\n type Jwk,\n type JwtSignerJwk,\n type JwtSignerWithJwk,\n Oauth2AuthorizationServer,\n Oauth2Client,\n Oauth2ErrorCodes,\n Oauth2ResourceServer,\n Oauth2ServerErrorResponseError,\n PkceCodeChallengeMethod,\n preAuthorizedCodeGrantIdentifier,\n} from '@openid4vc/oauth2'\nimport {\n type CredentialConfigurationSupportedWithFormats,\n type CredentialConfigurationsSupportedWithFormats,\n type CredentialIssuerMetadata,\n type CredentialRequestFormatSpecific,\n type CredentialResponse,\n type DeferredCredentialResponse,\n extractScopesForCredentialConfigurationIds,\n getCredentialConfigurationsMatchingRequestFormat,\n Openid4vciDraftVersion,\n Openid4vciIssuer,\n type ParseCredentialRequestReturn,\n} from '@openid4vc/openid4vci'\nimport { OpenId4VcVerifierApi } from '../openid4vc-verifier'\nimport type {\n OpenId4VciCredentialConfigurationSupportedWithFormats,\n OpenId4VciCredentialIssuerMetadata,\n OpenId4VciCredentialOfferPayload,\n OpenId4VciMetadata,\n OpenId4VcJwtIssuer,\n VerifiedOpenId4VcCredentialHolderBinding,\n} from '../shared'\nimport { OpenId4VciCredentialFormatProfile } from '../shared'\nimport { dynamicOid4vciClientAuthentication, getOid4vcCallbacks } from '../shared/callbacks'\nimport { getCredentialConfigurationsSupportedForScopes, getOfferedCredentials } from '../shared/issuerMetadataUtils'\nimport { storeActorIdForContextCorrelationId } from '../shared/router'\nimport {\n credoJwtIssuerToOpenId4VcJwtIssuer,\n decodeJwtIssuer,\n encodeJwtIssuer,\n getProofTypeFromPublicJwk,\n getPublicJwkFromDid,\n getSupportedJwaSignatureAlgorithms,\n} from '../shared/utils'\nimport { OpenId4VcIssuanceSessionState } from './OpenId4VcIssuanceSessionState'\nimport { type OpenId4VcIssuanceSessionStateChangedEvent, OpenId4VcIssuerEvents } from './OpenId4VcIssuerEvents'\nimport { OpenId4VcIssuerModuleConfig } from './OpenId4VcIssuerModuleConfig'\nimport type {\n OpenId4VciAuthorizationCodeFlowConfig,\n OpenId4VciCreateCredentialOfferOptions,\n OpenId4VciCreateCredentialResponseOptions,\n OpenId4VciCreateDeferredCredentialResponseOptions,\n OpenId4VciCreateIssuerOptions,\n OpenId4VciCreateStatelessCredentialOfferOptions,\n OpenId4VciCredentialRequestAuthorization,\n OpenId4VciCredentialRequestToCredentialMapperOptions,\n OpenId4VciPreAuthorizedCodeFlowConfig,\n OpenId4VciSignCredentials,\n OpenId4VciSignW3cCredentials,\n} from './OpenId4VcIssuerServiceOptions'\nimport {\n OpenId4VcIssuanceSessionRecord,\n OpenId4VcIssuanceSessionRepository,\n OpenId4VcIssuerRecord,\n OpenId4VcIssuerRepository,\n} from './repository'\nimport { generateTxCode } from './util/txCode'\n\n/**\n * @internal\n */\n@injectable()\nexport class OpenId4VcIssuerService {\n private w3cCredentialService: W3cCredentialService\n private w3cV2CredentialService: W3cV2CredentialService\n private openId4VcIssuerConfig: OpenId4VcIssuerModuleConfig\n private openId4VcIssuerRepository: OpenId4VcIssuerRepository\n private openId4VcIssuanceSessionRepository: OpenId4VcIssuanceSessionRepository\n\n public constructor(\n w3cCredentialService: W3cCredentialService,\n w3cV2CredentialService: W3cV2CredentialService,\n openId4VcIssuerConfig: OpenId4VcIssuerModuleConfig,\n openId4VcIssuerRepository: OpenId4VcIssuerRepository,\n openId4VcIssuanceSessionRepository: OpenId4VcIssuanceSessionRepository\n ) {\n this.w3cCredentialService = w3cCredentialService\n this.w3cV2CredentialService = w3cV2CredentialService\n this.openId4VcIssuerConfig = openId4VcIssuerConfig\n this.openId4VcIssuerRepository = openId4VcIssuerRepository\n this.openId4VcIssuanceSessionRepository = openId4VcIssuanceSessionRepository\n }\n\n public async createStatelessCredentialOffer(\n agentContext: AgentContext,\n options: OpenId4VciCreateStatelessCredentialOfferOptions & { issuer: OpenId4VcIssuerRecord }\n ): Promise<{ credentialOffer: string; credentialOfferObject: OpenId4VciCredentialOfferPayload }> {\n const { authorizationCodeFlowConfig, issuer, credentialConfigurationIds } = options\n const vcIssuer = this.getIssuer(agentContext)\n const issuerMetadata = await this.getIssuerMetadata(agentContext, issuer)\n\n const uniqueOfferedCredentials = Array.from(new Set(options.credentialConfigurationIds))\n if (uniqueOfferedCredentials.length !== credentialConfigurationIds.length) {\n throw new CredoError('All offered credentials must have unique ids.')\n }\n\n // Check if all the offered credential configuration ids have a scope value. If not, it won't be possible to actually request\n // issuance of the credential later on\n extractScopesForCredentialConfigurationIds({\n credentialConfigurationIds: options.credentialConfigurationIds,\n issuerMetadata,\n throwOnConfigurationWithoutScope: true,\n })\n\n if (authorizationCodeFlowConfig.authorizationServerUrl === issuerMetadata.credentialIssuer.credential_issuer) {\n throw new CredoError(\n 'Stateless offers can only be created for external authorization servers. Make sure to configure an external authorization server on the issuer record, and provide the authoriation server url.'\n )\n }\n\n const { credentialOffer, credentialOfferObject } = await vcIssuer.createCredentialOffer({\n credentialConfigurationIds: options.credentialConfigurationIds,\n grants: {\n authorization_code: {\n authorization_server: authorizationCodeFlowConfig.authorizationServerUrl,\n },\n },\n credentialOfferScheme: options.baseUri,\n issuerMetadata,\n })\n\n return {\n credentialOffer,\n credentialOfferObject,\n }\n }\n\n public async createCredentialOffer(\n agentContext: AgentContext,\n options: OpenId4VciCreateCredentialOfferOptions & { issuer: OpenId4VcIssuerRecord }\n ) {\n const {\n preAuthorizedCodeFlowConfig,\n authorizationCodeFlowConfig,\n issuer,\n credentialConfigurationIds,\n version = 'v1.draft15',\n authorization,\n } = options\n if (!preAuthorizedCodeFlowConfig && !authorizationCodeFlowConfig) {\n throw new CredoError('Authorization Config or Pre-Authorized Config must be provided.')\n }\n\n const vcIssuer = this.getIssuer(agentContext)\n const issuerMetadata = await this.getIssuerMetadata(agentContext, issuer)\n\n const uniqueOfferedCredentials = Array.from(new Set(options.credentialConfigurationIds))\n if (uniqueOfferedCredentials.length !== credentialConfigurationIds.length) {\n throw new CredoError('All offered credentials must have unique ids.')\n }\n\n if (uniqueOfferedCredentials.length === 0) {\n throw new CredoError('You need to offer at least one credential.')\n }\n\n // We always use shortened URIs currently\n const credentialOfferId = utils.uuid()\n const hostedCredentialOfferUri = joinUriParts(issuerMetadata.credentialIssuer.credential_issuer, [\n this.openId4VcIssuerConfig.credentialOfferEndpointPath,\n credentialOfferId,\n ])\n\n // Check if all the offered credential configuration ids have a scope value. If not, it won't be possible to actually request\n // issuance of the credential later on. For pre-auth it's not needed to add a scope.\n if (options.authorizationCodeFlowConfig) {\n extractScopesForCredentialConfigurationIds({\n credentialConfigurationIds: options.credentialConfigurationIds,\n issuerMetadata,\n throwOnConfigurationWithoutScope: true,\n })\n }\n\n const grants = await this.getGrantsFromConfig(agentContext, {\n issuer,\n issuerMetadata,\n preAuthorizedCodeFlowConfig,\n authorizationCodeFlowConfig,\n })\n\n const { credentialOffer, credentialOfferObject } = await vcIssuer.createCredentialOffer({\n credentialConfigurationIds: options.credentialConfigurationIds,\n grants,\n credentialOfferUri: hostedCredentialOfferUri,\n credentialOfferScheme: options.baseUri,\n issuerMetadata: {\n ...issuerMetadata,\n originalDraftVersion:\n version === 'v1.draft11-14' ? Openid4vciDraftVersion.Draft11 : Openid4vciDraftVersion.Draft15,\n },\n })\n\n const createdAt = new Date()\n const expiresAt = utils.addSecondsToDate(\n createdAt,\n this.openId4VcIssuerConfig.statefulCredentialOfferExpirationInSeconds\n )\n\n const chainedAuthorizationServerConfig = issuer.chainedAuthorizationServerConfigs?.find(\n (config) => config.issuer === authorizationCodeFlowConfig?.authorizationServerUrl\n )\n\n const issuanceSessionRepository = this.openId4VcIssuanceSessionRepository\n const issuanceSession = new OpenId4VcIssuanceSessionRecord({\n createdAt,\n expiresAt,\n credentialOfferPayload: credentialOfferObject,\n credentialOfferUri: hostedCredentialOfferUri,\n credentialOfferId,\n issuerId: issuer.issuerId,\n state: OpenId4VcIssuanceSessionState.OfferCreated,\n authorization: credentialOfferObject.grants?.authorization_code?.issuer_state\n ? {\n issuerState: credentialOfferObject.grants?.authorization_code?.issuer_state,\n }\n : undefined,\n presentation: authorizationCodeFlowConfig?.requirePresentationDuringIssuance\n ? {\n required: true,\n }\n : undefined,\n dpop: authorization?.requireDpop\n ? {\n required: true,\n }\n : undefined,\n walletAttestation: authorization?.requireWalletAttestation\n ? {\n required: true,\n }\n : undefined,\n chainedIdentity: chainedAuthorizationServerConfig\n ? {\n externalAuthorizationServerUrl: chainedAuthorizationServerConfig.issuer,\n }\n : undefined,\n // TODO: how to mix pre-auth and auth? Need to do state checks\n preAuthorizedCode: credentialOfferObject.grants?.[preAuthorizedCodeGrantIdentifier]?.['pre-authorized_code'],\n userPin: preAuthorizedCodeFlowConfig?.txCode\n ? generateTxCode(agentContext, preAuthorizedCodeFlowConfig.txCode)\n : undefined,\n generateRefreshTokens: options.generateRefreshTokens,\n issuanceMetadata: options.issuanceMetadata,\n openId4VciVersion: version,\n })\n await issuanceSessionRepository.save(agentContext, issuanceSession)\n this.emitStateChangedEvent(agentContext, issuanceSession, null)\n\n return {\n issuanceSession,\n credentialOffer,\n }\n }\n\n public async createCredentialResponse(\n agentContext: AgentContext,\n options: OpenId4VciCreateCredentialResponseOptions & { issuanceSession: OpenId4VcIssuanceSessionRecord }\n ): Promise<{ issuanceSession: OpenId4VcIssuanceSessionRecord; credentialResponse: CredentialResponse }> {\n options.issuanceSession.assertState([\n // OfferUriRetrieved is valid when doing auth flow (we should add a check)\n OpenId4VcIssuanceSessionState.OfferUriRetrieved,\n OpenId4VcIssuanceSessionState.AccessTokenCreated,\n OpenId4VcIssuanceSessionState.CredentialRequestReceived,\n // It is possible to issue multiple credentials in one session\n OpenId4VcIssuanceSessionState.CredentialsPartiallyIssued,\n ])\n const { issuanceSession } = options\n const issuer = await this.getIssuerByIssuerId(agentContext, options.issuanceSession.issuerId)\n const vcIssuer = this.getIssuer(agentContext, { issuanceSessionId: issuanceSession.id })\n const issuerMetadata = await this.getIssuerMetadata(agentContext, issuer)\n\n const parsedCredentialRequest = vcIssuer.parseCredentialRequest({\n issuerMetadata,\n credentialRequest: options.credentialRequest,\n })\n const {\n credentialRequest,\n credentialIdentifier,\n\n format,\n } = parsedCredentialRequest\n\n if (credentialIdentifier) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidCredentialRequest,\n error_description: `Using unsupported 'credential_identifier'`,\n })\n }\n\n if (credentialRequest.format && !format && !parsedCredentialRequest.credentialConfigurationId) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.UnsupportedCredentialFormat,\n error_description: `Unsupported credential request based on format '${credentialRequest.format}'`,\n })\n }\n\n if (parsedCredentialRequest.credentialConfigurationId && !parsedCredentialRequest.credentialConfiguration) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.UnsupportedCredentialFormat,\n error_description: `Unsupported credential request based on credential configuration id ${credentialRequest.credential_configuration_id}`,\n })\n }\n\n const { credentialConfiguration, credentialConfigurationId } = this.getCredentialConfigurationsForRequest({\n issuanceSession,\n issuerMetadata,\n requestFormat: format,\n credentialConfigurations:\n parsedCredentialRequest.credentialConfiguration && parsedCredentialRequest.credentialConfigurationId\n ? {\n [parsedCredentialRequest.credentialConfigurationId]: parsedCredentialRequest.credentialConfiguration,\n }\n : undefined,\n authorization: options.authorization,\n })\n\n const verifiedCredentialRequestProofs = await this.verifyCredentialRequestProofs(agentContext, {\n issuanceSession,\n issuer,\n parsedCredentialRequest,\n credentialConfiguration,\n credentialConfigurationId,\n })\n\n const mapper =\n options.credentialRequestToCredentialMapper ?? this.openId4VcIssuerConfig.credentialRequestToCredentialMapper\n\n let verification: OpenId4VciCredentialRequestToCredentialMapperOptions['verification']\n\n // NOTE: this will throw an error if the verifier module is not registered and there is a\n // verification session. But you can't get here without the verifier module anyway\n if (issuanceSession.presentation?.openId4VcVerificationSessionId) {\n const verifierApi = agentContext.dependencyManager.resolve(OpenId4VcVerifierApi)\n const session = await verifierApi.getVerificationSessionById(\n issuanceSession.presentation.openId4VcVerificationSessionId\n )\n\n const response = await verifierApi.getVerifiedAuthorizationResponse(\n issuanceSession.presentation.openId4VcVerificationSessionId\n )\n\n if (response.presentationExchange) {\n verification = {\n session,\n presentationExchange: response.presentationExchange,\n }\n } else if (response.dcql) {\n verification = {\n session,\n dcql: response.dcql,\n }\n } else {\n throw new CredoError(\n `Verified authorization response for verification session with id '${session.id}' does not have presentationExchange or dcql defined.`\n )\n }\n }\n\n const signOptionsOrDeferral = await mapper({\n agentContext,\n issuanceSession,\n holderBinding: verifiedCredentialRequestProofs,\n credentialOffer: issuanceSession.credentialOfferPayload,\n\n verification,\n\n credentialRequest: options.credentialRequest,\n credentialRequestFormat: format,\n\n // Matching credential configuration\n credentialConfiguration,\n credentialConfigurationId,\n\n // Authorization\n authorization: options.authorization,\n })\n\n let credentialResponse: CredentialResponse\n\n // NOTE: nonce in credential response is deprecated in newer drafts, but for now we keep it in\n const { cNonce, cNonceExpiresInSeconds } = await this.createNonce(agentContext, issuer)\n\n if (signOptionsOrDeferral.type === 'deferral') {\n credentialResponse = vcIssuer.createCredentialResponse({\n transactionId: signOptionsOrDeferral.transactionId,\n interval: signOptionsOrDeferral.interval,\n cNonce,\n cNonceExpiresInSeconds,\n credentialRequest: parsedCredentialRequest,\n })\n\n // Save transaction data for deferred issuance\n issuanceSession.transactions.push({\n transactionId: signOptionsOrDeferral.transactionId,\n numberOfCredentials: verifiedCredentialRequestProofs.keys.length,\n credentialConfigurationId,\n })\n\n // Determine new state\n const newState =\n issuanceSession.state === OpenId4VcIssuanceSessionState.CredentialsPartiallyIssued\n ? OpenId4VcIssuanceSessionState.CredentialsPartiallyIssued\n : OpenId4VcIssuanceSessionState.CredentialRequestReceived\n\n // Update expiry time to allow for re-check\n await this.updateExpiresAt(agentContext, issuanceSession, signOptionsOrDeferral.interval)\n\n // Update state\n await this.updateState(agentContext, issuanceSession, newState)\n } else {\n const credentials = await this.getSignedCredentials(agentContext, signOptionsOrDeferral, {\n issuanceSession,\n credentialConfiguration,\n expectedLength: verifiedCredentialRequestProofs.keys.length,\n })\n\n credentialResponse = vcIssuer.createCredentialResponse({\n credential: credentialRequest.proof ? credentials.credentials[0] : undefined,\n credentials: credentialRequest.proofs\n ? issuanceSession.openId4VciVersion === 'v1' || issuanceSession.openId4VciVersion === 'v1.draft15'\n ? credentials.credentials.map((c) => ({ credential: c }))\n : credentials.credentials\n : undefined,\n cNonce,\n cNonceExpiresInSeconds,\n credentialRequest: parsedCredentialRequest,\n })\n\n issuanceSession.issuedCredentials.push(credentialConfigurationId)\n const newState =\n issuanceSession.issuedCredentials.length >=\n issuanceSession.credentialOfferPayload.credential_configuration_ids.length\n ? OpenId4VcIssuanceSessionState.Completed\n : OpenId4VcIssuanceSessionState.CredentialsPartiallyIssued\n await this.updateState(agentContext, issuanceSession, newState)\n }\n\n return {\n credentialResponse,\n issuanceSession,\n }\n }\n\n public async createDeferredCredentialResponse(\n agentContext: AgentContext,\n options: OpenId4VciCreateDeferredCredentialResponseOptions & { issuanceSession: OpenId4VcIssuanceSessionRecord }\n ): Promise<{\n issuanceSession: OpenId4VcIssuanceSessionRecord\n deferredCredentialResponse: DeferredCredentialResponse\n }> {\n options.issuanceSession.assertState([\n OpenId4VcIssuanceSessionState.CredentialRequestReceived,\n OpenId4VcIssuanceSessionState.CredentialsPartiallyIssued,\n ])\n const transaction = options.issuanceSession.transactions.find(\n (tx) => tx.transactionId === options.deferredCredentialRequest.transaction_id\n )\n if (!transaction) {\n throw new CredoError('OpenId4VcIssuanceSessionRecord does not contain transaction with given transaction_id.')\n }\n\n const { issuanceSession } = options\n const issuer = await this.getIssuerByIssuerId(agentContext, options.issuanceSession.issuerId)\n const vcIssuer = this.getIssuer(agentContext, { issuanceSessionId: issuanceSession.id })\n\n const credentialConfigurationId = transaction.credentialConfigurationId\n const credentialConfiguration = issuer.credentialConfigurationsSupported[transaction.credentialConfigurationId]\n if (!credentialConfiguration) {\n throw new CredoError(\n 'Issuer does not contain credential configuration for the given credential configuration id.'\n )\n }\n\n const mapper =\n options.deferredCredentialRequestToCredentialMapper ??\n this.openId4VcIssuerConfig.deferredCredentialRequestToCredentialMapper\n if (!mapper) {\n throw new CredoError(\n 'OpenId4VcIssuerService does not have a defined deferredCredentialRequestToCredentialMapper.'\n )\n }\n\n const signOptionsOrDeferral = await mapper({\n agentContext,\n issuanceSession,\n deferredCredentialRequest: options.deferredCredentialRequest,\n authorization: options.authorization,\n })\n\n let deferredCredentialResponse: DeferredCredentialResponse\n if (signOptionsOrDeferral.type === 'deferral') {\n deferredCredentialResponse = vcIssuer.createDeferredCredentialResponse({\n interval: signOptionsOrDeferral.interval,\n transactionId: signOptionsOrDeferral.transactionId,\n })\n\n // Update expiry time to allow for re-check\n await this.updateExpiresAt(agentContext, issuanceSession, signOptionsOrDeferral.interval)\n } else {\n const credentials = await this.getSignedCredentials(agentContext, signOptionsOrDeferral, {\n issuanceSession,\n credentialConfiguration,\n expectedLength: transaction.numberOfCredentials,\n })\n\n deferredCredentialResponse = vcIssuer.createDeferredCredentialResponse({\n credentials: credentials.credentials.map((c) => ({ credential: c })),\n })\n\n issuanceSession.issuedCredentials.push(credentialConfigurationId)\n\n // Remove the transaction from the session, as it is now completed\n issuanceSession.transactions = issuanceSession.transactions?.filter(\n (tx) => tx.transactionId !== transaction.transactionId\n )\n\n // Determine new state\n const newState =\n issuanceSession.issuedCredentials.length >=\n issuanceSession.credentialOfferPayload.credential_configuration_ids.length\n ? OpenId4VcIssuanceSessionState.Completed\n : OpenId4VcIssuanceSessionState.CredentialsPartiallyIssued\n\n await this.updateState(agentContext, issuanceSession, newState)\n }\n\n return {\n deferredCredentialResponse,\n issuanceSession,\n }\n }\n\n private async verifyCredentialRequestProofs(\n agentContext: AgentContext,\n options: {\n parsedCredentialRequest: ParseCredentialRequestReturn\n issuer: OpenId4VcIssuerRecord\n issuanceSession: OpenId4VcIssuanceSessionRecord\n credentialConfigurationId: string\n credentialConfiguration: CredentialConfigurationSupportedWithFormats\n }\n ): Promise<VerifiedOpenId4VcCredentialHolderBinding> {\n const { parsedCredentialRequest, issuer, issuanceSession, credentialConfiguration, credentialConfigurationId } =\n options\n const { proofs } = parsedCredentialRequest\n\n const vcIssuer = this.getIssuer(agentContext, { issuanceSessionId: issuanceSession.id })\n const issuerMetadata = await this.getIssuerMetadata(agentContext, issuer)\n\n const allowedProofTypes = credentialConfiguration.proof_types_supported ?? {\n jwt: { proof_signing_alg_values_supported: getSupportedJwaSignatureAlgorithms(agentContext) },\n }\n\n const [proofType, proofValue] = (Object.entries(proofs ?? {})[0] as [string, string[]] | undefined) ?? []\n if (!proofType || !proofValue || proofValue.length === 0) {\n const { cNonce, cNonceExpiresInSeconds } = await this.createNonce(agentContext, issuer)\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description: 'Missing required proof(s) in credential request',\n c_nonce: cNonce,\n c_nonce_expires_in: cNonceExpiresInSeconds,\n })\n }\n\n if (proofType !== 'jwt' && proofType !== 'attestation') {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description: `Proof type '${proofType}' is not supported `,\n })\n }\n\n const supportedProofType = allowedProofTypes[proofType]\n if (!supportedProofType) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description: `Proof type '${proofType}' is not supported for credential configuration '${credentialConfigurationId}'`,\n })\n }\n\n if (proofType === 'attestation' && proofValue.length !== 1) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description: \"Only a single proofs entry is supported for proof type 'attestation'\",\n })\n }\n\n await this.updateState(agentContext, issuanceSession, OpenId4VcIssuanceSessionState.CredentialRequestReceived)\n\n if (proofType === 'attestation') {\n const keyAttestationJwt = proofValue[0]\n const keyAttestation = await vcIssuer.verifyCredentialRequestAttestationProof({\n issuerMetadata,\n keyAttestationJwt,\n })\n\n if (!supportedProofType.proof_signing_alg_values_supported.includes(keyAttestation.header.alg)) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description: `Proof signing alg value '${keyAttestation.header.alg}' is not supported for proof type 'attestation' in credential configuration '${credentialConfigurationId}'`,\n })\n }\n\n if (!keyAttestation.payload.nonce) {\n const { cNonce, cNonceExpiresInSeconds } = await this.createNonce(agentContext, issuer)\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description:\n 'Missing nonce in attestation proof in credential request. If no nonce is present in the attestation, use the jwt proof type instead',\n c_nonce: cNonce,\n c_nonce_expires_in: cNonceExpiresInSeconds,\n })\n }\n\n if (supportedProofType.key_attestations_required && keyAttestation) {\n const expectedKeyStorage = supportedProofType.key_attestations_required.key_storage\n const expectedUserAuthentication = supportedProofType.key_attestations_required.user_authentication\n\n if (\n expectedKeyStorage &&\n !expectedKeyStorage.some((keyStorage) => keyAttestation.payload.key_storage?.includes(keyStorage))\n ) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description: `Insufficient key_storage for key attestation. Proof type 'attestation' for credential configuration '${credentialConfigurationId}', expects one of key_storage values ${expectedKeyStorage.join(', ')}`,\n })\n }\n\n if (\n expectedUserAuthentication &&\n !expectedUserAuthentication.some((userAuthentication) =>\n keyAttestation.payload.user_authentication?.includes(userAuthentication)\n )\n ) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description: `Insufficient user_authentication for key attestation. Proof type 'attestation' for credential configuration '${credentialConfigurationId}', expects one of user_authentication values ${expectedUserAuthentication.join(', ')}`,\n })\n }\n }\n\n await this.verifyNonce(agentContext, issuer, keyAttestation.payload.nonce).catch(async (error) => {\n const { cNonce, cNonceExpiresInSeconds } = await this.createNonce(agentContext, issuer)\n throw new Oauth2ServerErrorResponseError(\n {\n error: Oauth2ErrorCodes.InvalidNonce,\n error_description: 'Invalid nonce in credential request',\n c_nonce: cNonce,\n c_nonce_expires_in: cNonceExpiresInSeconds,\n },\n {\n cause: error,\n }\n )\n })\n\n return {\n bindingMethod: 'jwk',\n keys: keyAttestation.payload.attested_keys.map((attestedKey) => {\n return {\n method: 'jwk',\n jwk: Kms.PublicJwk.fromUnknown(attestedKey),\n }\n }),\n proofType: 'attestation',\n\n // It's up to the credential request mapper to ensure we trust the key attestation signer\n // For x5c it's kinda covered already.\n keyAttestation,\n }\n }\n\n if (proofType === 'jwt') {\n let firstNonce: string | undefined\n const proofSigners: Array<(JwtSignerWithJwk & { method: 'did' }) | JwtSignerJwk> = []\n\n for (const jwt of proofValue) {\n const { signer, payload, header, keyAttestation } = await vcIssuer.verifyCredentialRequestJwtProof({\n issuerMetadata,\n jwt,\n clientId: options.issuanceSession.clientId,\n })\n\n // TODO: we should probably do this check before signature verification, but we then we\n // first need to decode the jwt\n if (!supportedProofType.proof_signing_alg_values_supported.includes(header.alg)) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description: `Proof signing alg value '${header.alg}' is not supported for proof type 'jwt' in credential configuration '${credentialConfigurationId}'`,\n })\n }\n\n if (signer.method !== 'jwk' && signer.method !== 'did') {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description: \"Only 'jwk' and 'did' binding methods supported for jwt proof\",\n })\n }\n\n if (proofSigners[0] && signer.method !== proofSigners[0].method) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description:\n \"All proofs must be signed using the same binding method. Found a mix of 'did' and 'jwk'\",\n })\n }\n\n if (proofSigners[0] && signer.alg !== proofSigners[0].alg) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description:\n \"All proofs must be signed using the same alg value. Found a mix of different 'alg' values.\",\n })\n }\n\n if (keyAttestation && signer.method === 'did') {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description: \"Binding method 'did' is not supported when a key attestation is provided.\",\n })\n }\n\n if (supportedProofType.key_attestations_required && !keyAttestation) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description: `Missing required key attestation. Key attestations are required for proof type 'jwt' in credential configuration '${credentialConfigurationId}'`,\n })\n }\n\n if (supportedProofType.key_attestations_required && keyAttestation) {\n const expectedKeyStorage = supportedProofType.key_attestations_required.key_storage\n const expectedUserAuthentication = supportedProofType.key_attestations_required.user_authentication\n\n if (\n expectedKeyStorage &&\n !expectedKeyStorage.some((keyStorage) => keyAttestation.payload.key_storage?.includes(keyStorage))\n ) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description: `Insufficient key_storage for key attestation. Proof type 'jwt' for credential configuration '${credentialConfigurationId}', expects one of key_storage values ${expectedKeyStorage.join(', ')}`,\n })\n }\n\n if (\n expectedUserAuthentication &&\n !expectedUserAuthentication.some((userAuthentication) =>\n keyAttestation.payload.user_authentication?.includes(userAuthentication)\n )\n ) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description: `Insufficient user_authentication for key attestation. Proof type 'jwt' for credential configuration '${credentialConfigurationId}', expects one of user_authentication values ${expectedUserAuthentication.join(', ')}`,\n })\n }\n }\n\n if (keyAttestation && proofValue.length > 1) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description:\n \"Only a single proofs entry is supported when jwt proof header contains 'key_attestation'\",\n })\n }\n\n if (!payload.nonce) {\n const { cNonce, cNonceExpiresInSeconds } = await this.createNonce(agentContext, issuer)\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description: 'Missing nonce in proof(s) in credential request',\n c_nonce: cNonce,\n c_nonce_expires_in: cNonceExpiresInSeconds,\n })\n }\n\n // Set previous nonce if not yet set (first iteration)\n if (!firstNonce) firstNonce = payload.nonce\n if (firstNonce !== payload.nonce) {\n const { cNonce, cNonceExpiresInSeconds } = await this.createNonce(agentContext, issuer)\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description: 'Not all nonce values in proofs are equal',\n c_nonce: cNonce,\n c_nonce_expires_in: cNonceExpiresInSeconds,\n })\n }\n\n // IF nonce is provided in the key attestation (not required with jwt proof) then\n // it MUST match with the nonce of the JWT proof\n if (keyAttestation?.payload.nonce && keyAttestation.payload.nonce !== payload.nonce) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description:\n 'If a nonce is present in the key attestation, the nonce in the proof jwt must be equal to the nonce in the key attestation',\n })\n }\n\n // Verify the nonce\n await this.verifyNonce(agentContext, issuer, payload.nonce).catch(async (error) => {\n const { cNonce, cNonceExpiresInSeconds } = await this.createNonce(agentContext, issuer)\n throw new Oauth2ServerErrorResponseError(\n {\n error: Oauth2ErrorCodes.InvalidNonce,\n error_description: 'Invalid nonce in credential request',\n c_nonce: cNonce,\n c_nonce_expires_in: cNonceExpiresInSeconds,\n },\n {\n cause: error,\n }\n )\n })\n\n if (keyAttestation) {\n return {\n proofType: 'jwt',\n bindingMethod: 'jwk',\n keys: keyAttestation.payload.attested_keys.map((attestedKey) => {\n return {\n method: 'jwk',\n jwk: Kms.PublicJwk.fromUnknown(attestedKey),\n }\n }),\n keyAttestation,\n }\n }\n proofSigners.push(signer)\n }\n\n if (proofSigners[0].method === 'did') {\n const signers = proofSigners as Array<JwtSignerWithJwk & { method: 'did' }>\n return {\n proofType: 'jwt',\n bindingMethod: 'did',\n keys: signers.map((signer) => ({\n didUrl: signer.didUrl,\n method: 'did',\n jwk: Kms.PublicJwk.fromUnknown(signer.publicJwk),\n })),\n }\n }\n\n return {\n proofType: 'jwt',\n bindingMethod: 'jwk',\n keys: (proofSigners as JwtSignerJwk[]).map((signer) => {\n return {\n method: 'jwk',\n jwk: Kms.PublicJwk.fromUnknown(signer.publicJwk),\n }\n }),\n }\n }\n\n // This will not happen, but to make TS happy\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidProof,\n error_description: 'Missing required proof(s) in credential request',\n })\n }\n\n public async findIssuanceSessionsByQuery(\n agentContext: AgentContext,\n query: Query<OpenId4VcIssuanceSessionRecord>,\n queryOptions?: QueryOptions\n ) {\n return this.openId4VcIssuanceSessionRepository.findByQuery(agentContext, query, queryOptions)\n }\n\n public async findSingleIssuanceSessionByQuery(\n agentContext: AgentContext,\n query: Query<OpenId4VcIssuanceSessionRecord>\n ) {\n return this.openId4VcIssuanceSessionRepository.findSingleByQuery(agentContext, query)\n }\n\n public async getIssuanceSessionById(agentContext: AgentContext, issuanceSessionId: string) {\n return this.openId4VcIssuanceSessionRepository.getById(agentContext, issuanceSessionId)\n }\n\n public async getAllIssuers(agentContext: AgentContext) {\n return this.openId4VcIssuerRepository.getAll(agentContext)\n }\n\n public async getIssuerByIssuerId(agentContext: AgentContext, issuerId: string) {\n return this.openId4VcIssuerRepository.getByIssuerId(agentContext, issuerId)\n }\n\n public async updateIssuer(agentContext: AgentContext, issuer: OpenId4VcIssuerRecord) {\n if (issuer.signedMetadata) {\n const issuerMetadata = await this.getIssuerMetadata(agentContext, issuer, false)\n issuer.signedMetadata = await this.createSignedMetadata(\n agentContext,\n issuerMetadata.credentialIssuer,\n decodeJwtIssuer(issuer.signedMetadata.signer)\n )\n }\n\n await this.openId4VcIssuerRepository.update(agentContext, issuer)\n }\n\n public async createIssuer(agentContext: AgentContext, options: OpenId4VciCreateIssuerOptions) {\n const kms = agentContext.resolve(Kms.KeyManagementApi)\n\n // TODO: ideally we can store additional data with a key, such as:\n // - createdAt\n // - purpose\n const accessTokenSignerKey = await kms.createKey({\n type: options.accessTokenSignerKeyType ?? { kty: 'OKP', crv: 'Ed25519' },\n })\n\n const openId4VcIssuer = new OpenId4VcIssuerRecord({\n issuerId: options.issuerId ?? utils.uuid(),\n display: options.display,\n dpopSigningAlgValuesSupported: options.dpopSigningAlgValuesSupported,\n accessTokenPublicJwk: accessTokenSignerKey.publicJwk,\n authorizationServerConfigs: options.authorizationServerConfigs,\n credentialConfigurationsSupported: options.credentialConfigurationsSupported,\n batchCredentialIssuance: options.batchCredentialIssuance,\n })\n\n if (options.metadataSigner) {\n const issuerMetadata = await this.getIssuerMetadata(agentContext, openId4VcIssuer, false)\n openId4VcIssuer.signedMetadata = await this.createSignedMetadata(\n agentContext,\n issuerMetadata.credentialIssuer,\n options.metadataSigner\n )\n }\n\n await this.openId4VcIssuerRepository.save(agentContext, openId4VcIssuer)\n await storeActorIdForContextCorrelationId(agentContext, openId4VcIssuer.issuerId)\n return openId4VcIssuer\n }\n\n private async createSignedMetadata(\n agentContext: AgentContext,\n credentialIssuerMetadata: OpenId4VciCredentialIssuerMetadata,\n metadataSigner: OpenId4VcJwtIssuer\n ) {\n const issuer = this.getIssuer(agentContext)\n const credentialIssuerMetadataJwt = await issuer.createSignedCredentialIssuerMetadataJwt({\n credentialIssuerMetadata,\n signer: await credoJwtIssuerToOpenId4VcJwtIssuer(agentContext, metadataSigner),\n })\n\n return {\n jwt: credentialIssuerMetadataJwt,\n signer: encodeJwtIssuer(metadataSigner),\n }\n }\n\n public async rotateAccessTokenSigningKey(\n agentContext: AgentContext,\n issuer: OpenId4VcIssuerRecord,\n options?: Pick<OpenId4VciCreateIssuerOptions, 'accessTokenSignerKeyType'>\n ) {\n const kms = agentContext.resolve(Kms.KeyManagementApi)\n\n const previousKey = issuer.resolvedAccessTokenPublicJwk\n const accessTokenSignerKey = await kms.createKey({\n type: options?.accessTokenSignerKeyType ?? { kty: 'OKP', crv: 'Ed25519' },\n })\n\n issuer.accessTokenPublicJwk = accessTokenSignerKey.publicJwk\n await this.openId4VcIssuerRepository.update(agentContext, issuer)\n\n // Remove previous key\n await kms.deleteKey({\n keyId: previousKey.keyId,\n })\n }\n\n /**\n * @param fetchExternalAuthorizationServerMetadata defaults to false\n */\n public async getIssuerMetadata(\n agentContext: AgentContext,\n issuerRecord: OpenId4VcIssuerRecord,\n fetchExternalAuthorizationServerMetadata = false\n ) {\n const config = agentContext.dependencyManager.resolve(OpenId4VcIssuerModuleConfig)\n const issuerUrl = joinUriParts(config.baseUrl, [issuerRecord.issuerId])\n const oauth2Client = this.getOauth2Client(agentContext)\n const directAuthorizationServerConfigs = issuerRecord.directAuthorizationServerConfigs\n\n const extraAuthorizationServers: AuthorizationServerMetadata[] =\n fetchExternalAuthorizationServerMetadata && directAuthorizationServerConfigs\n ? await Promise.all(\n directAuthorizationServerConfigs.map(async (server) => {\n const metadata = await oauth2Client.fetchAuthorizationServerMetadata(server.issuer)\n if (!metadata)\n throw new CredoError(`Authorization server metadata not found for issuer '${server.issuer}'`)\n return metadata\n })\n )\n : []\n\n const authorizationServers =\n directAuthorizationServerConfigs && directAuthorizationServerConfigs.length > 0\n ? [\n ...directAuthorizationServerConfigs.map((authorizationServer) => authorizationServer.issuer),\n // Our issuer is also a valid authorization server (for pre-auth and chained auth)\n issuerUrl,\n ]\n : undefined\n\n const credentialIssuerMetadata = {\n credential_issuer: issuerUrl,\n credential_endpoint: joinUriParts(issuerUrl, [config.credentialEndpointPath]),\n deferred_credential_endpoint: joinUriParts(issuerUrl, [config.deferredCredentialEndpointPath]),\n credential_configurations_supported: issuerRecord.credentialConfigurationsSupported ?? {},\n authorization_servers: authorizationServers,\n display: issuerRecord.display,\n nonce_endpoint: joinUriParts(issuerUrl, [config.nonceEndpointPath]),\n batch_credential_issuance: issuerRecord.batchCredentialIssuance\n ? {\n batch_size: issuerRecord.batchCredentialIssuance.batchSize,\n }\n : undefined,\n } satisfies CredentialIssuerMetadata\n\n const issuerAuthorizationServer = {\n issuer: issuerUrl,\n token_endpoint: joinUriParts(issuerUrl, [config.accessTokenEndpointPath]),\n 'pre-authorized_grant_anonymous_access_supported': true,\n\n jwks_uri: joinUriParts(issuerUrl, [config.jwksEndpointPath]),\n\n grant_types_supported: [authorizationCodeGrantIdentifier, preAuthorizedCodeGrantIdentifier],\n\n authorization_challenge_endpoint: joinUriParts(issuerUrl, [config.authorizationChallengeEndpointPath]),\n authorization_endpoint: joinUriParts(issuerUrl, [config.authorizationEndpoint]),\n\n pushed_authorization_request_endpoint: joinUriParts(issuerUrl, [config.pushedAuthorizationRequestEndpoint]),\n require_pushed_authorization_requests: true,\n\n code_challenge_methods_supported: [PkceCodeChallengeMethod.S256],\n dpop_signing_alg_values_supported: issuerRecord.dpopSigningAlgValuesSupported,\n } satisfies AuthorizationServerMetadata\n\n return {\n originalDraftVersion: Openid4vciDraftVersion.V1,\n credentialIssuer: credentialIssuerMetadata,\n authorizationServers: [issuerAuthorizationServer, ...extraAuthorizationServers],\n knownCredentialConfigurations: credentialIssuerMetadata.credential_configurations_supported,\n\n signedMetadataJwt: issuerRecord.signedMetadata?.jwt,\n }\n }\n\n public async createNonce(agentContext: AgentContext, issuer: OpenId4VcIssuerRecord) {\n const issuerMetadata = await this.getIssuerMetadata(agentContext, issuer)\n const jwsService = agentContext.dependencyManager.resolve(JwsService)\n\n const cNonceExpiresInSeconds = this.openId4VcIssuerConfig.cNonceExpiresInSeconds\n const cNonceExpiresAt = utils.addSecondsToDate(new Date(), cNonceExpiresInSeconds)\n\n const key = issuer.resolvedAccessTokenPublicJwk\n const cNonce = await jwsService.createJwsCompact(agentContext, {\n keyId: key.keyId,\n payload: JwtPayload.fromJson({\n iss: issuerMetadata.credentialIssuer.credential_issuer,\n exp: utils.dateToSeconds(cNonceExpiresAt),\n }),\n protectedHeaderOptions: {\n typ: 'credo+cnonce',\n kid: key.keyId,\n alg: key.signatureAlgorithm,\n },\n })\n\n return {\n cNonce,\n cNonceExpiresAt,\n cNonceExpiresInSeconds,\n }\n }\n\n /**\n * @todo nonces are very short lived (1 min), but it might be nice to also cache the nonces\n * in the cache if we have 'seen' them. They will only be in the cache for a short time\n * and it will prevent replay\n */\n private async verifyNonce(agentContext: AgentContext, issuer: OpenId4VcIssuerRecord, cNonce: string) {\n const issuerMetadata = await this.getIssuerMetadata(agentContext, issuer)\n const jwsService = agentContext.dependencyManager.resolve(JwsService)\n\n const key = issuer.resolvedAccessTokenPublicJwk\n const jwt = Jwt.fromSerializedJwt(cNonce)\n jwt.payload.validate({\n skewSeconds: agentContext.config.validitySkewSeconds,\n })\n\n if (jwt.payload.iss !== issuerMetadata.credentialIssuer.credential_issuer) {\n throw new CredoError(`Invalid 'iss' claim in cNonce jwt`)\n }\n if (jwt.header.typ !== 'credo+cnonce') {\n throw new CredoError(`Invalid 'typ' claim in cNonce jwt header`)\n }\n\n const verification = await jwsService.verifyJws(agentContext, {\n jws: cNonce,\n jwsSigner: {\n method: 'jwk',\n jwk: key,\n },\n })\n\n if (!verification.isValid) {\n throw new CredoError('Invalid nonce')\n }\n }\n\n public async createRefreshToken(\n agentContext: AgentContext,\n issuer: OpenId4VcIssuerRecord,\n options: {\n issuerState?: string\n preAuthorizedCode?: string\n dpop?: {\n jwk: Jwk\n }\n }\n ) {\n const issuerMetadata = await this.getIssuerMetadata(agentContext, issuer)\n const jwsService = agentContext.dependencyManager.resolve(JwsService)\n\n const expiresInSeconds = this.openId4VcIssuerConfig.refreshTokenExpiresInSeconds\n const expiresAt = utils.addSecondsToDate(new Date(), expiresInSeconds)\n\n const key = issuer.resolvedAccessTokenPublicJwk\n const refreshToken = await jwsService.createJwsCompact(agentContext, {\n keyId: key.keyId,\n payload: JwtPayload.fromJson({\n iss: issuerMetadata.credentialIssuer.credential_issuer,\n aud: issuerMetadata.credentialIssuer.credential_issuer,\n exp: utils.dateToSeconds(expiresAt),\n issuer_state: options.issuerState,\n 'pre-authorized_code': options.preAuthorizedCode,\n cnf: options.dpop\n ? {\n jkt: await calculateJwkThumbprint({\n hashAlgorithm: HashAlgorithm.Sha256,\n hashCallback: getOid4vcCallbacks(agentContext).hash,\n jwk: options.dpop.jwk,\n }),\n }\n : undefined,\n }),\n protectedHeaderOptions: {\n typ: 'credo+refresh_token',\n kid: key.keyId,\n alg: key.signatureAlgorithm,\n },\n })\n\n return refreshToken\n }\n\n public parseRefreshToken(agentContext: AgentContext, token: string) {\n const jwt = Jwt.fromSerializedJwt(token)\n jwt.payload.validate({\n skewSeconds: agentContext.config.validitySkewSeconds,\n })\n\n if (!jwt.payload.exp) {\n throw new CredoError(`Missing 'exp' claim in refresh token jwt`)\n }\n if (jwt.header.typ !== 'credo+refresh_token') {\n throw new CredoError(`Invalid 'typ' claim in refresh token jwt header`)\n }\n\n const { 'pre-authorized_code': preAuthorizedCode, issuer_state: issuerState, cnf } = jwt.payload.additionalClaims\n\n if (preAuthorizedCode && typeof preAuthorizedCode !== 'string') {\n throw new CredoError(`Invalid 'pre-authorized_code' claim in refresh token jwt payload`)\n }\n\n if (issuerState && typeof issuerState !== 'string') {\n throw new CredoError(`Invalid 'issuer_state' claim in refresh token jwt payload`)\n }\n\n if (!preAuthorizedCode && !issuerState) {\n throw new CredoError(`Missing 'issuer_state' or 'pre-authorized_code' claim in refresh token jwt payload`)\n }\n\n let jwkThumbprint: string | undefined\n if (cnf) {\n if (typeof cnf !== 'object' || !('jkt' in cnf) || typeof cnf.jkt !== 'string') {\n throw new CredoError(`Invalid 'cnf' claim in refresh token jwt payload`)\n }\n\n jwkThumbprint = cnf.jkt\n }\n\n return {\n jwt,\n expiresAt: new Date(jwt.payload.exp * 1000),\n issuerState: issuerState as string | undefined,\n preAuthorizedCode: preAuthorizedCode as string | undefined,\n dpop: jwkThumbprint\n ? {\n jwkThumbprint,\n }\n : undefined,\n }\n }\n\n public async verifyRefreshToken(\n agentContext: AgentContext,\n issuer: OpenId4VcIssuerRecord,\n parsedRefreshToken: ReturnType<OpenId4VcIssuerService['parseRefreshToken']>,\n options: {\n dpop?: {\n jwkThumbprint?: string\n }\n } = {}\n ) {\n const issuerMetadata = await this.getIssuerMetadata(agentContext, issuer)\n const jwsService = agentContext.dependencyManager.resolve(JwsService)\n\n const key = issuer.resolvedAccessTokenPublicJwk\n\n if (parsedRefreshToken.jwt.payload.iss !== issuerMetadata.credentialIssuer.credential_issuer) {\n throw new CredoError(`Invalid 'iss' claim in refresh token jwt`)\n }\n if (parsedRefreshToken.jwt.payload.aud !== issuerMetadata.credentialIssuer.credential_issuer) {\n throw new CredoError(`Invalid 'aud' claim in refresh token jwt`)\n }\n\n const verification = await jwsService.verifyJws(agentContext, {\n jws: parsedRefreshToken.jwt.serializedJwt,\n jwsSigner: {\n method: 'jwk',\n jwk: key,\n },\n })\n\n if (!verification.isValid) {\n throw new CredoError('Invalid refresh token')\n }\n\n if (options.dpop?.jwkThumbprint) {\n if (parsedRefreshToken.dpop?.jwkThumbprint !== options.dpop.jwkThumbprint) {\n throw new CredoError(`Invalid 'cnf.jkt' claim in refresh token jwt payload`)\n }\n }\n }\n\n public getIssuer(agentContext: AgentContext, options: { issuanceSessionId?: string } = {}) {\n return new Openid4vciIssuer({\n callbacks: getOid4vcCallbacks(agentContext, options),\n })\n }\n\n public getOauth2Client(agentContext: AgentContext, issuerRecord?: OpenId4VcIssuerRecord) {\n return new Oauth2Client({\n callbacks: {\n ...getOid4vcCallbacks(agentContext),\n ...(issuerRecord\n ? { clientAuthentication: dynamicOid4vciClientAuthentication(agentContext, issuerRecord) }\n : {}),\n },\n })\n }\n\n public getOauth2AuthorizationServer(agentContext: AgentContext, options: { issuanceSessionId?: string } = {}) {\n return new Oauth2AuthorizationServer({\n callbacks: getOid4vcCallbacks(agentContext, options),\n })\n }\n\n public getResourceServer(agentContext: AgentContext, issuerRecord: OpenId4VcIssuerRecord) {\n return new Oauth2ResourceServer({\n callbacks: {\n ...getOid4vcCallbacks(agentContext),\n clientAuthentication: dynamicOid4vciClientAuthentication(agentContext, issuerRecord),\n },\n })\n }\n\n /**\n * Update the expiresAt field of the issuance session to ensure it remains\n * valid during the deferral process. We set it to the maximum between the\n * current expiresAt and the current time plus the configured expiration\n * time or the interval multiplied by 2. This accounts for the chance of multiple\n * deferrals happening, with longer intervals.\n */\n private async updateExpiresAt(\n agentContext: AgentContext,\n issuanceSession: OpenId4VcIssuanceSessionRecord,\n interval: number\n ) {\n const expiresAt =\n issuanceSession.expiresAt ??\n utils.addSecondsToDate(\n issuanceSession.createdAt,\n this.openId4VcIssuerConfig.statefulCredentialOfferExpirationInSeconds\n )\n\n issuanceSession.expiresAt = new Date(\n Math.max(\n expiresAt.getTime(),\n utils\n .addSecondsToDate(\n new Date(),\n Math.max(this.openId4VcIssuerConfig.statefulCredentialOfferExpirationInSeconds, interval * 2)\n )\n .getTime()\n )\n )\n\n await this.openId4VcIssuanceSessionRepository.update(agentContext, issuanceSession)\n }\n\n /**\n * Update the record to a new state and emit an state changed event. Also updates the record\n * in storage.\n */\n public async updateState(\n agentContext: AgentContext,\n issuanceSession: OpenId4VcIssuanceSessionRecord,\n newState: OpenId4VcIssuanceSessionState\n ) {\n agentContext.config.logger.debug(\n `Updating openid4vc issuance session record ${issuanceSession.id} to state ${newState} (previous=${issuanceSession.state})`\n )\n\n const previousState = issuanceSession.state\n issuanceSession.state = newState\n await this.openId4VcIssuanceSessionRepository.update(agentContext, issuanceSession)\n\n this.emitStateChangedEvent(agentContext, issuanceSession, previousState)\n }\n\n public emitStateChangedEvent(\n agentContext: AgentContext,\n issuanceSession: OpenId4VcIssuanceSessionRecord,\n previousState: OpenId4VcIssuanceSessionState | null\n ) {\n const eventEmitter = agentContext.dependencyManager.resolve(EventEmitter)\n\n eventEmitter.emit<OpenId4VcIssuanceSessionStateChangedEvent>(agentContext, {\n type: OpenId4VcIssuerEvents.IssuanceSessionStateChanged,\n payload: {\n issuanceSession: issuanceSession.clone(),\n previousState: previousState,\n },\n })\n }\n\n private async getGrantsFromConfig(\n agentContext: AgentContext,\n config: {\n issuer: OpenId4VcIssuerRecord\n issuerMetadata: OpenId4VciMetadata\n preAuthorizedCodeFlowConfig?: OpenId4VciPreAuthorizedCodeFlowConfig\n authorizationCodeFlowConfig?: OpenId4VciAuthorizationCodeFlowConfig\n }\n ) {\n const kms = agentContext.resolve(Kms.KeyManagementApi)\n const { preAuthorizedCodeFlowConfig, authorizationCodeFlowConfig, issuer, issuerMetadata } = config\n\n // TODO: export type\n const grants: Parameters<Openid4vciIssuer['createCredentialOffer']>[0]['grants'] = {}\n\n // Pre auth\n if (preAuthorizedCodeFlowConfig) {\n const { txCode, authorizationServerUrl, preAuthorizedCode } = preAuthorizedCodeFlowConfig\n\n grants[preAuthorizedCodeGrantIdentifier] = {\n 'pre-authorized_code': preAuthorizedCode ?? TypedArrayEncoder.toBase64URL(kms.randomBytes({ length: 32 })),\n tx_code: txCode,\n authorization_server: config.issuerMetadata.credentialIssuer.authorization_servers\n ? authorizationServerUrl\n : undefined,\n }\n }\n\n // Auth\n if (authorizationCodeFlowConfig) {\n const { requirePresentationDuringIssuance } = authorizationCodeFlowConfig\n let authorizationServerUrl = authorizationCodeFlowConfig.authorizationServerUrl\n\n if (requirePresentationDuringIssuance) {\n if (authorizationServerUrl && authorizationServerUrl !== issuerMetadata.credentialIssuer.credential_issuer) {\n throw new CredoError(\n `When 'requirePresentationDuringIssuance' is set, 'authorizationServerUrl' must be undefined or match the credential issuer identifier`\n )\n }\n\n authorizationServerUrl = issuerMetadata.credentialIssuer.credential_issuer\n }\n\n const authorizationServerConfig = issuer.authorizationServerConfigs?.find(\n (server) => server.issuer === authorizationServerUrl\n )\n if (authorizationServerConfig?.type === 'chained') {\n authorizationServerUrl = issuerMetadata.credentialIssuer.credential_issuer\n }\n\n grants.authorization_code = {\n issuer_state:\n // TODO: the issuer_state should not be guessable, so it's best if we generate it and now allow the user to provide it?\n // but same is true for the pre-auth code and users of credo can also provide that value. We can't easily do unique constraint with askat\n authorizationCodeFlowConfig.issuerState ?? TypedArrayEncoder.toBase64URL(kms.randomBytes({ length: 32 })),\n authorization_server: config.issuerMetadata.credentialIssuer.authorization_servers\n ? authorizationServerUrl\n : undefined,\n }\n }\n\n return grants\n }\n\n private getCredentialConfigurationsForRequest(options: {\n issuerMetadata: OpenId4VciMetadata\n issuanceSession: OpenId4VcIssuanceSessionRecord\n authorization: OpenId4VciCredentialRequestAuthorization\n requestFormat?: CredentialRequestFormatSpecific\n credentialConfigurations?: CredentialConfigurationsSupportedWithFormats\n }): { credentialConfigurationId: string; credentialConfiguration: CredentialConfigurationSupportedWithFormats } {\n const { requestFormat, issuanceSession, issuerMetadata, authorization, credentialConfigurations } = options\n\n // Check against all credential configurations\n const configurationsMatchingRequest = credentialConfigurations\n ? credentialConfigurations\n : requestFormat\n ? getCredentialConfigurationsMatchingRequestFormat({\n requestFormat,\n issuerMetadata,\n })\n : undefined\n\n if (!configurationsMatchingRequest) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidCredentialRequest,\n error_description: `Either 'credential_configuration_id' or 'format' needs to be defined'`,\n })\n }\n\n if (Object.keys(configurationsMatchingRequest).length === 0) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidCredentialRequest,\n error_description: 'Credential request does not match any credential configuration',\n })\n }\n\n // Limit to offered configurations\n const configurationsMatchingRequestAndOffer = getOfferedCredentials(\n issuanceSession.credentialOfferPayload.credential_configuration_ids,\n configurationsMatchingRequest,\n { ignoreNotFoundIds: true }\n )\n if (Object.keys(configurationsMatchingRequestAndOffer).length === 0) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidCredentialRequest,\n error_description: 'Credential request does not match any credential configurations from credential offer',\n })\n }\n\n // Limit to not-issued and not-deferred configurations\n const deferredCredentialConfigurationIds = issuanceSession.transactions.map((tx) => tx.credentialConfigurationId)\n const configurationsMatchingRequestAndOfferNotIssued = getOfferedCredentials(\n issuanceSession.credentialOfferPayload.credential_configuration_ids.filter(\n (id) => !issuanceSession.issuedCredentials.includes(id) && !deferredCredentialConfigurationIds.includes(id)\n ),\n configurationsMatchingRequestAndOffer,\n { ignoreNotFoundIds: true }\n )\n if (Object.keys(configurationsMatchingRequestAndOfferNotIssued).length === 0) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidCredentialRequest,\n error_description:\n 'Credential request does not match any credential configurations from credential offer that have not been issued yet',\n })\n }\n\n // For pre-auth we allow all ids from the offer\n if (authorization.accessToken.payload['pre-authorized_code']) {\n // We return the first one that matches all checks. Pre draft 15 it could be multiple entries, but only if you offer\n // multiple credentials of the same type. We need to do checks on this, so we pick the first one\n const [credentialConfigurationId, credentialConfiguration] = Object.entries(\n configurationsMatchingRequestAndOfferNotIssued\n )[0]\n return {\n credentialConfigurationId,\n credentialConfiguration,\n }\n }\n\n // Limit to scopes from the token\n // We only do this for auth flow, so it's not required to add a scope for every configuration.\n const configurationsMatchingRequestOfferScope = getCredentialConfigurationsSupportedForScopes(\n configurationsMatchingRequestAndOfferNotIssued,\n authorization.accessToken.payload.scope?.split(' ') ?? []\n )\n if (Object.keys(configurationsMatchingRequestOfferScope).length === 0) {\n throw new Oauth2ServerErrorResponseError(\n {\n error: Oauth2ErrorCodes.InsufficientScope,\n error_description:\n 'Scope does not grant issuance for any requested credential configurations from credential offer',\n },\n {\n status: 403,\n }\n )\n }\n\n // We return the first one that matches all checks. Pre draft 15 it could be multiple entries, but only if you offer\n // multiple credentials of the same type. We need to do checks on this, so we pick the first one\n const [credentialConfigurationId, credentialConfiguration] = Object.entries(\n configurationsMatchingRequestOfferScope\n )[0]\n return {\n credentialConfigurationId,\n credentialConfiguration: credentialConfiguration as CredentialConfigurationSupportedWithFormats,\n }\n }\n\n private async getSignedCredentials(\n agentContext: AgentContext,\n signOptions: OpenId4VciSignCredentials,\n options: {\n issuanceSession: OpenId4VcIssuanceSessionRecord\n credentialConfiguration: OpenId4VciCredentialConfigurationSupportedWithFormats\n expectedLength: number\n }\n ): Promise<{\n credentials: string[] | Record<string, unknown>[]\n format: `${OpenId4VciCredentialFormatProfile}`\n }> {\n const { credentialConfiguration, expectedLength } = options\n\n // NOTE: we may want to allow a mismatch between this (as there is a match batch length), but for now it needs to match\n if (signOptions.credentials.length !== expectedLength) {\n throw new CredoError(\n `Credential request to credential mapper returned '${signOptions.credentials.length}' to be signed, while '${expectedLength}' holder binding entries were provided. Make sure to return one credential for each holder binding entry`\n )\n }\n\n if (signOptions.format === ClaimFormat.JwtVc || signOptions.format === ClaimFormat.LdpVc) {\n const oid4vciFormatMap: Record<string, ClaimFormat.JwtVc | ClaimFormat.LdpVc> = {\n [OpenId4VciCredentialFormatProfile.JwtVcJson]: ClaimFormat.JwtVc,\n [OpenId4VciCredentialFormatProfile.JwtVcJsonLd]: ClaimFormat.JwtVc,\n [OpenId4VciCredentialFormatProfile.LdpVc]: ClaimFormat.LdpVc,\n }\n\n const expectedClaimFormat = oid4vciFormatMap[credentialConfiguration.format]\n if (signOptions.format !== expectedClaimFormat) {\n throw new CredoError(\n `Invalid credential format returned by sign options. Expected '${expectedClaimFormat}', received '${signOptions.format}'.`\n )\n }\n\n return {\n format: credentialConfiguration.format,\n credentials: (await Promise.all(\n signOptions.credentials.map((credential) =>\n this.signW3cCredential(agentContext, signOptions.format, credential).then((signed) => signed.encoded)\n )\n )) as string[] | Record<string, unknown>[],\n }\n }\n if (signOptions.format === ClaimFormat.SdJwtDc) {\n if (\n credentialConfiguration.format !== OpenId4VciCredentialFormatProfile.SdJwtVc &&\n credentialConfiguration.format !== OpenId4VciCredentialFormatProfile.SdJwtDc\n ) {\n throw new CredoError(\n `Invalid credential format returned by sign options. Expected '${ClaimFormat.SdJwtDc}', received '${signOptions.format}'.`\n )\n }\n\n if (!signOptions.credentials.every((c) => c.payload.vct === credentialConfiguration.vct)) {\n throw new CredoError(\n `One or more vct values of the offered credential(s) do not match the vct of the requested credential. Offered ${Array.from(\n new Set(signOptions.credentials.map((c) => `'${c.payload.vct}'`))\n ).join(', ')} Requested '${credentialConfiguration.vct}'.`\n )\n }\n\n const sdJwtVcApi = agentContext.dependencyManager.resolve(SdJwtVcApi)\n return {\n format: credentialConfiguration.format,\n credentials: await Promise.all(\n signOptions.credentials.map((credential) =>\n sdJwtVcApi\n .sign({\n ...credential,\n // Set header type based on the oid4vci format\n headerType: credentialConfiguration.format,\n })\n .then((signed) => signed.compact)\n )\n ),\n }\n }\n if (signOptions.format === ClaimFormat.MsoMdoc) {\n if (signOptions.format !== credentialConfiguration.format) {\n throw new CredoError(\n `Invalid credential format returned by sign options. Expected '${credentialConfiguration.format}', received '${signOptions.format}'.`\n )\n }\n if (!signOptions.credentials.every((c) => c.docType === credentialConfiguration.doctype)) {\n throw new CredoError(\n `One or more doctype values of the offered credential(s) do not match the doctype of the requested credential. Offered ${Array.from(\n new Set(signOptions.credentials.map((c) => `'${c.docType}'`))\n ).join(', ')} Requested '${credentialConfiguration.doctype}'.`\n )\n }\n\n const mdocApi = agentContext.dependencyManager.resolve(MdocApi)\n return {\n format: OpenId4VciCredentialFormatProfile.MsoMdoc,\n credentials: await Promise.all(\n signOptions.credentials.map((credential) => mdocApi.sign(credential).then((signed) => signed.base64Url))\n ),\n }\n }\n if (signOptions.format === ClaimFormat.SdJwtW3cVc) {\n return {\n format: credentialConfiguration.format,\n credentials: (await Promise.all(\n signOptions.credentials.map((credential) =>\n this.w3cV2CredentialService\n .signCredential(agentContext, {\n format: ClaimFormat.SdJwtW3cVc,\n ...credential,\n })\n .then((signed) => signed.encoded)\n )\n )) as string[] | Record<string, unknown>[],\n }\n }\n throw new CredoError(`Unsupported credential format ${signOptions.format}`)\n }\n\n private async signW3cCredential(\n agentContext: AgentContext,\n format: `${ClaimFormat.JwtVc}` | `${ClaimFormat.LdpVc}`,\n options: OpenId4VciSignW3cCredentials['credentials'][number]\n ) {\n const publicJwk = await getPublicJwkFromDid(agentContext, options.verificationMethod)\n if (format === ClaimFormat.JwtVc) {\n return await this.w3cCredentialService.signCredential(agentContext, {\n format: ClaimFormat.JwtVc,\n credential: options.credential,\n verificationMethod: options.verificationMethod,\n alg: publicJwk.signatureAlgorithm,\n })\n }\n\n const proofType = getProofTypeFromPublicJwk(agentContext, publicJwk)\n return await this.w3cCredentialService.signCredential(agentContext, {\n format: ClaimFormat.LdpVc,\n credential: options.credential,\n verificationMethod: options.verificationMethod,\n proofType: proofType,\n })\n }\n}\n"],"mappings":"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"}
|
|
@@ -48,7 +48,7 @@ function handleTokenRequest(config) {
|
|
|
48
48
|
break;
|
|
49
49
|
case refreshTokenGrantIdentifier:
|
|
50
50
|
allowedStates = [OpenId4VcIssuanceSessionState.CredentialRequestReceived, OpenId4VcIssuanceSessionState.CredentialsPartiallyIssued];
|
|
51
|
-
parsedRefreshToken = openId4VcIssuerService.parseRefreshToken(grant.refreshToken);
|
|
51
|
+
parsedRefreshToken = openId4VcIssuerService.parseRefreshToken(agentContext, grant.refreshToken);
|
|
52
52
|
query = {
|
|
53
53
|
preAuthorizedCode: parsedRefreshToken.preAuthorizedCode,
|
|
54
54
|
authorizationCode: parsedRefreshToken.issuerState
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"accessTokenEndpoint.mjs","names":["allowedStates: OpenId4VcIssuanceSessionState[]","query: Query<OpenId4VcIssuanceSessionRecord>","parsedRefreshToken: ReturnType<OpenId4VcIssuerService['parseRefreshToken']> | undefined","verificationResult: VerifyAccessTokenRequestReturn","refreshToken: string | undefined"],"sources":["../../../src/openid4vc-issuer/router/accessTokenEndpoint.ts"],"sourcesContent":["import { CredoError, joinUriParts, type Query, utils } from '@credo-ts/core'\nimport type { HttpMethod, Jwk, VerifyAccessTokenRequestReturn } from '@openid4vc/oauth2'\nimport {\n authorizationCodeGrantIdentifier,\n Oauth2ErrorCodes,\n Oauth2ServerErrorResponseError,\n preAuthorizedCodeGrantIdentifier,\n refreshTokenGrantIdentifier,\n} from '@openid4vc/oauth2'\nimport type { NextFunction, Response, Router } from 'express'\nimport {\n getRequestContext,\n sendJsonResponse,\n sendOauth2ErrorResponse,\n sendUnknownServerErrorResponse,\n} from '../../shared/router'\nimport { OpenId4VcIssuanceSessionState } from '../OpenId4VcIssuanceSessionState'\nimport type { OpenId4VcIssuerModuleConfig } from '../OpenId4VcIssuerModuleConfig'\nimport { OpenId4VcIssuerService } from '../OpenId4VcIssuerService'\nimport { OpenId4VcIssuanceSessionRecord, OpenId4VcIssuanceSessionRepository } from '../repository'\nimport type { OpenId4VcIssuanceRequest } from './requestContext'\n\nexport function configureAccessTokenEndpoint(router: Router, config: OpenId4VcIssuerModuleConfig) {\n router.post(config.accessTokenEndpointPath, handleTokenRequest(config))\n}\n\nexport function handleTokenRequest(config: OpenId4VcIssuerModuleConfig) {\n return async (request: OpenId4VcIssuanceRequest, response: Response, next: NextFunction) => {\n response.set({ 'Cache-Control': 'no-store', Pragma: 'no-cache' })\n const requestContext = getRequestContext(request)\n const { agentContext, issuer } = requestContext\n\n try {\n const openId4VcIssuerService = agentContext.dependencyManager.resolve(OpenId4VcIssuerService)\n const issuanceSessionRepository = agentContext.dependencyManager.resolve(OpenId4VcIssuanceSessionRepository)\n const issuerMetadata = await openId4VcIssuerService.getIssuerMetadata(agentContext, issuer)\n const accessTokenSigningKey = issuer.resolvedAccessTokenPublicJwk\n let oauth2AuthorizationServer = openId4VcIssuerService.getOauth2AuthorizationServer(agentContext)\n\n const fullRequestUrl = joinUriParts(issuerMetadata.credentialIssuer.credential_issuer, [\n config.accessTokenEndpointPath,\n ])\n const requestLike = {\n headers: new Headers(request.headers as Record<string, string>),\n method: request.method as HttpMethod,\n url: fullRequestUrl,\n } as const\n\n const { accessTokenRequest, grant, dpop, clientAttestation, pkceCodeVerifier } =\n oauth2AuthorizationServer.parseAccessTokenRequest({\n accessTokenRequest: request.body,\n request: requestLike,\n })\n\n let allowedStates: OpenId4VcIssuanceSessionState[]\n let query: Query<OpenId4VcIssuanceSessionRecord>\n let parsedRefreshToken: ReturnType<OpenId4VcIssuerService['parseRefreshToken']> | undefined\n\n switch (grant.grantType) {\n case preAuthorizedCodeGrantIdentifier:\n allowedStates = [OpenId4VcIssuanceSessionState.OfferCreated, OpenId4VcIssuanceSessionState.OfferUriRetrieved]\n query = { preAuthorizedCode: grant.preAuthorizedCode }\n break\n case authorizationCodeGrantIdentifier:\n allowedStates = [OpenId4VcIssuanceSessionState.AuthorizationGranted]\n query = { authorizationCode: grant.code }\n break\n case refreshTokenGrantIdentifier:\n allowedStates = [\n OpenId4VcIssuanceSessionState.CredentialRequestReceived,\n OpenId4VcIssuanceSessionState.CredentialsPartiallyIssued,\n ]\n parsedRefreshToken = openId4VcIssuerService.parseRefreshToken(grant.refreshToken)\n query = {\n preAuthorizedCode: parsedRefreshToken.preAuthorizedCode,\n authorizationCode: parsedRefreshToken.issuerState,\n }\n break\n default:\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.UnsupportedGrantType,\n error_description: 'Unsupported grant type',\n })\n }\n\n const issuanceSession = await issuanceSessionRepository.findSingleByQuery(agentContext, query)\n if (!issuanceSession || !allowedStates.includes(issuanceSession.state)) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidGrant,\n error_description: 'Invalid authorization code',\n })\n }\n\n const expiresAt =\n issuanceSession.expiresAt ??\n utils.addSecondsToDate(issuanceSession.createdAt, config.statefulCredentialOfferExpirationInSeconds)\n\n if (Date.now() > expiresAt.getTime()) {\n issuanceSession.errorMessage = 'Credential offer has expired'\n await openId4VcIssuerService.updateState(agentContext, issuanceSession, OpenId4VcIssuanceSessionState.Error)\n throw new Oauth2ServerErrorResponseError({\n // What is the best error here?\n error: Oauth2ErrorCodes.InvalidGrant,\n error_description: 'Session expired',\n })\n }\n\n oauth2AuthorizationServer = openId4VcIssuerService.getOauth2AuthorizationServer(agentContext, {\n issuanceSessionId: issuanceSession.id,\n })\n let verificationResult: VerifyAccessTokenRequestReturn\n\n if (grant.grantType === preAuthorizedCodeGrantIdentifier) {\n if (!issuanceSession.preAuthorizedCode) {\n throw new Oauth2ServerErrorResponseError(\n {\n error: Oauth2ErrorCodes.InvalidGrant,\n error_description: 'Invalid authorization code',\n },\n {\n internalMessage:\n 'Found issuance session without preAuthorizedCode. This should not happen as the issuance session is fetched based on the pre authorized code',\n }\n )\n }\n\n verificationResult = await oauth2AuthorizationServer.verifyPreAuthorizedCodeAccessTokenRequest({\n accessTokenRequest,\n expectedPreAuthorizedCode: issuanceSession.preAuthorizedCode,\n grant,\n request: requestLike,\n authorizationServerMetadata: issuerMetadata.authorizationServers[0],\n clientAttestation: {\n ...clientAttestation,\n // First session config, fall back to global config\n required: issuanceSession.walletAttestation?.required ?? config.walletAttestationsRequired,\n\n // NOTE: we might want to enforce this? Not sure\n // ensureConfirmationKeyMatchesDpopKey: true\n },\n dpop: {\n ...dpop,\n // First session config, fall back to global config\n required: issuanceSession.dpop?.required ?? config.dpopRequired,\n },\n expectedTxCode: issuanceSession.userPin,\n preAuthorizedCodeExpiresAt:\n issuanceSession.expiresAt ??\n utils.addSecondsToDate(issuanceSession.createdAt, config.statefulCredentialOfferExpirationInSeconds),\n })\n } else if (grant.grantType === authorizationCodeGrantIdentifier) {\n if (!issuanceSession.authorization?.code || !issuanceSession.authorization?.codeExpiresAt) {\n throw new Oauth2ServerErrorResponseError(\n {\n error: Oauth2ErrorCodes.InvalidGrant,\n error_description: 'Invalid authorization code',\n },\n {\n internalMessage:\n 'Found issuance session without authorization.code or authorization.codeExpiresAt. This should not happen as the issuance session is fetched based on the authorization code',\n }\n )\n }\n verificationResult = await oauth2AuthorizationServer.verifyAuthorizationCodeAccessTokenRequest({\n accessTokenRequest,\n expectedCode: issuanceSession.authorization.code,\n codeExpiresAt: issuanceSession.authorization.codeExpiresAt,\n grant,\n authorizationServerMetadata: issuerMetadata.authorizationServers[0],\n request: requestLike,\n clientAttestation: {\n ...clientAttestation,\n\n // Ensure it matches the previously provided client id\n // FIXME: we don't verify that the attestation is issued by the same party\n expectedClientId: issuanceSession.clientId,\n\n // NOTE: we don't look at the global config here. As we already checked and\n // set required to true previously if client attestations were provided or required.\n required: issuanceSession.walletAttestation?.required,\n\n // NOTE: we might want to enforce this? Not sure\n // ensureConfirmationKeyMatchesDpopKey: true\n },\n dpop: {\n ...dpop,\n // NOTE: we don't look at the global config here. As we already checked and\n // set required to true previously if client attestations were provided or required.\n required: issuanceSession.dpop?.required,\n\n // Ensure it matches previously provided jwk thumbprint\n expectedJwkThumbprint: issuanceSession.dpop?.dpopJkt,\n },\n pkce: issuanceSession.pkce\n ? {\n codeChallenge: issuanceSession.pkce.codeChallenge,\n codeChallengeMethod: issuanceSession.pkce.codeChallengeMethod,\n codeVerifier: pkceCodeVerifier,\n }\n : undefined,\n })\n } else if (grant.grantType === refreshTokenGrantIdentifier) {\n if (!parsedRefreshToken) {\n throw new CredoError('Refresh token verification is required for refresh token grant type')\n }\n\n verificationResult = await oauth2AuthorizationServer.verifyRefreshTokenAccessTokenRequest({\n accessTokenRequest,\n // Refresh token validity is already checked before\n expectedRefreshToken: grant.refreshToken,\n grant,\n request: requestLike,\n authorizationServerMetadata: issuerMetadata.authorizationServers[0],\n clientAttestation: {\n ...clientAttestation,\n // First session config, fall back to global config\n required: issuanceSession.walletAttestation?.required ?? config.walletAttestationsRequired,\n\n // NOTE: we might want to enforce this? Not sure\n // ensureConfirmationKeyMatchesDpopKey: true\n },\n dpop: {\n ...dpop,\n // First session config, fall back to global config\n required: issuanceSession.dpop?.required ?? config.dpopRequired,\n },\n refreshTokenExpiresAt: parsedRefreshToken?.expiresAt,\n })\n\n await openId4VcIssuerService.verifyRefreshToken(agentContext, issuer, parsedRefreshToken, {\n dpop: verificationResult.dpop,\n })\n } else {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.UnsupportedGrantType,\n error_description: 'Unsupported grant type',\n })\n }\n\n // Do not update the session state if the grant type is refresh token. This\n // avoids the session state going \"backwards\".\n if (grant.grantType !== refreshTokenGrantIdentifier) {\n await openId4VcIssuerService.updateState(\n agentContext,\n issuanceSession,\n OpenId4VcIssuanceSessionState.AccessTokenRequested\n )\n }\n\n const { cNonce, cNonceExpiresInSeconds } = await openId4VcIssuerService.createNonce(agentContext, issuer)\n\n // for authorization code flow we take the authorization scopes. For pre-auth we don't use scopes (we just\n // use the offered credential configuration ids so a scope is not required)\n const scopes =\n grant.grantType === authorizationCodeGrantIdentifier ? issuanceSession.authorization?.scopes : undefined\n const subject = `credo:${utils.uuid()}`\n\n const tokenDpop = verificationResult.dpop\n ? {\n jwk: verificationResult.dpop?.jwk,\n }\n : undefined\n\n // Generate a refresh token if they're enabled in the config and the grant type is not refresh token\n let refreshToken: string | undefined\n if (issuanceSession.generateRefreshTokens && grant.grantType !== refreshTokenGrantIdentifier) {\n refreshToken = await openId4VcIssuerService.createRefreshToken(agentContext, issuer, {\n preAuthorizedCode: grant.grantType === preAuthorizedCodeGrantIdentifier ? grant.preAuthorizedCode : undefined,\n issuerState: issuanceSession.authorization?.issuerState,\n dpop: tokenDpop,\n })\n }\n\n const signerJwk = accessTokenSigningKey\n const accessTokenResponse = await oauth2AuthorizationServer.createAccessTokenResponse({\n audience: issuerMetadata.credentialIssuer.credential_issuer,\n authorizationServer: issuerMetadata.credentialIssuer.credential_issuer,\n expiresInSeconds: config.accessTokenExpiresInSeconds,\n signer: {\n method: 'jwk',\n alg: signerJwk.supportedSignatureAlgorithms[0],\n publicJwk: signerJwk.toJson() as Jwk,\n },\n dpop: tokenDpop,\n scope: scopes?.join(' '),\n clientId: issuanceSession.clientId,\n\n additionalAccessTokenPayload: {\n 'pre-authorized_code':\n grant.grantType === preAuthorizedCodeGrantIdentifier\n ? grant.preAuthorizedCode\n : parsedRefreshToken?.preAuthorizedCode,\n issuer_state: issuanceSession.authorization?.issuerState,\n },\n // We generate a random subject for each access token and bind the issuance session to this.\n subject,\n\n refreshToken,\n\n // NOTE: these have been removed in newer drafts. Keeping them in for now\n cNonce,\n cNonceExpiresIn: cNonceExpiresInSeconds,\n })\n\n issuanceSession.authorization = {\n ...issuanceSession.authorization,\n subject,\n }\n\n await openId4VcIssuerService.updateState(\n agentContext,\n issuanceSession,\n // Retain the current session state when refreshing the access token.\n grant.grantType === refreshTokenGrantIdentifier\n ? issuanceSession.state\n : OpenId4VcIssuanceSessionState.AccessTokenCreated\n )\n\n return sendJsonResponse(response, next, accessTokenResponse)\n } catch (error) {\n if (error instanceof Oauth2ServerErrorResponseError) {\n return sendOauth2ErrorResponse(response, next, agentContext.config.logger, error)\n }\n\n return sendUnknownServerErrorResponse(response, next, agentContext.config.logger, error)\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"accessTokenEndpoint.mjs","names":["allowedStates: OpenId4VcIssuanceSessionState[]","query: Query<OpenId4VcIssuanceSessionRecord>","parsedRefreshToken: ReturnType<OpenId4VcIssuerService['parseRefreshToken']> | undefined","verificationResult: VerifyAccessTokenRequestReturn","refreshToken: string | undefined"],"sources":["../../../src/openid4vc-issuer/router/accessTokenEndpoint.ts"],"sourcesContent":["import { CredoError, joinUriParts, type Query, utils } from '@credo-ts/core'\nimport type { HttpMethod, Jwk, VerifyAccessTokenRequestReturn } from '@openid4vc/oauth2'\nimport {\n authorizationCodeGrantIdentifier,\n Oauth2ErrorCodes,\n Oauth2ServerErrorResponseError,\n preAuthorizedCodeGrantIdentifier,\n refreshTokenGrantIdentifier,\n} from '@openid4vc/oauth2'\nimport type { NextFunction, Response, Router } from 'express'\nimport {\n getRequestContext,\n sendJsonResponse,\n sendOauth2ErrorResponse,\n sendUnknownServerErrorResponse,\n} from '../../shared/router'\nimport { OpenId4VcIssuanceSessionState } from '../OpenId4VcIssuanceSessionState'\nimport type { OpenId4VcIssuerModuleConfig } from '../OpenId4VcIssuerModuleConfig'\nimport { OpenId4VcIssuerService } from '../OpenId4VcIssuerService'\nimport { OpenId4VcIssuanceSessionRecord, OpenId4VcIssuanceSessionRepository } from '../repository'\nimport type { OpenId4VcIssuanceRequest } from './requestContext'\n\nexport function configureAccessTokenEndpoint(router: Router, config: OpenId4VcIssuerModuleConfig) {\n router.post(config.accessTokenEndpointPath, handleTokenRequest(config))\n}\n\nexport function handleTokenRequest(config: OpenId4VcIssuerModuleConfig) {\n return async (request: OpenId4VcIssuanceRequest, response: Response, next: NextFunction) => {\n response.set({ 'Cache-Control': 'no-store', Pragma: 'no-cache' })\n const requestContext = getRequestContext(request)\n const { agentContext, issuer } = requestContext\n\n try {\n const openId4VcIssuerService = agentContext.dependencyManager.resolve(OpenId4VcIssuerService)\n const issuanceSessionRepository = agentContext.dependencyManager.resolve(OpenId4VcIssuanceSessionRepository)\n const issuerMetadata = await openId4VcIssuerService.getIssuerMetadata(agentContext, issuer)\n const accessTokenSigningKey = issuer.resolvedAccessTokenPublicJwk\n let oauth2AuthorizationServer = openId4VcIssuerService.getOauth2AuthorizationServer(agentContext)\n\n const fullRequestUrl = joinUriParts(issuerMetadata.credentialIssuer.credential_issuer, [\n config.accessTokenEndpointPath,\n ])\n const requestLike = {\n headers: new Headers(request.headers as Record<string, string>),\n method: request.method as HttpMethod,\n url: fullRequestUrl,\n } as const\n\n const { accessTokenRequest, grant, dpop, clientAttestation, pkceCodeVerifier } =\n oauth2AuthorizationServer.parseAccessTokenRequest({\n accessTokenRequest: request.body,\n request: requestLike,\n })\n\n let allowedStates: OpenId4VcIssuanceSessionState[]\n let query: Query<OpenId4VcIssuanceSessionRecord>\n let parsedRefreshToken: ReturnType<OpenId4VcIssuerService['parseRefreshToken']> | undefined\n\n switch (grant.grantType) {\n case preAuthorizedCodeGrantIdentifier:\n allowedStates = [OpenId4VcIssuanceSessionState.OfferCreated, OpenId4VcIssuanceSessionState.OfferUriRetrieved]\n query = { preAuthorizedCode: grant.preAuthorizedCode }\n break\n case authorizationCodeGrantIdentifier:\n allowedStates = [OpenId4VcIssuanceSessionState.AuthorizationGranted]\n query = { authorizationCode: grant.code }\n break\n case refreshTokenGrantIdentifier:\n allowedStates = [\n OpenId4VcIssuanceSessionState.CredentialRequestReceived,\n OpenId4VcIssuanceSessionState.CredentialsPartiallyIssued,\n ]\n parsedRefreshToken = openId4VcIssuerService.parseRefreshToken(agentContext, grant.refreshToken)\n query = {\n preAuthorizedCode: parsedRefreshToken.preAuthorizedCode,\n authorizationCode: parsedRefreshToken.issuerState,\n }\n break\n default:\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.UnsupportedGrantType,\n error_description: 'Unsupported grant type',\n })\n }\n\n const issuanceSession = await issuanceSessionRepository.findSingleByQuery(agentContext, query)\n if (!issuanceSession || !allowedStates.includes(issuanceSession.state)) {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.InvalidGrant,\n error_description: 'Invalid authorization code',\n })\n }\n\n const expiresAt =\n issuanceSession.expiresAt ??\n utils.addSecondsToDate(issuanceSession.createdAt, config.statefulCredentialOfferExpirationInSeconds)\n\n if (Date.now() > expiresAt.getTime()) {\n issuanceSession.errorMessage = 'Credential offer has expired'\n await openId4VcIssuerService.updateState(agentContext, issuanceSession, OpenId4VcIssuanceSessionState.Error)\n throw new Oauth2ServerErrorResponseError({\n // What is the best error here?\n error: Oauth2ErrorCodes.InvalidGrant,\n error_description: 'Session expired',\n })\n }\n\n oauth2AuthorizationServer = openId4VcIssuerService.getOauth2AuthorizationServer(agentContext, {\n issuanceSessionId: issuanceSession.id,\n })\n let verificationResult: VerifyAccessTokenRequestReturn\n\n if (grant.grantType === preAuthorizedCodeGrantIdentifier) {\n if (!issuanceSession.preAuthorizedCode) {\n throw new Oauth2ServerErrorResponseError(\n {\n error: Oauth2ErrorCodes.InvalidGrant,\n error_description: 'Invalid authorization code',\n },\n {\n internalMessage:\n 'Found issuance session without preAuthorizedCode. This should not happen as the issuance session is fetched based on the pre authorized code',\n }\n )\n }\n\n verificationResult = await oauth2AuthorizationServer.verifyPreAuthorizedCodeAccessTokenRequest({\n accessTokenRequest,\n expectedPreAuthorizedCode: issuanceSession.preAuthorizedCode,\n grant,\n request: requestLike,\n authorizationServerMetadata: issuerMetadata.authorizationServers[0],\n clientAttestation: {\n ...clientAttestation,\n // First session config, fall back to global config\n required: issuanceSession.walletAttestation?.required ?? config.walletAttestationsRequired,\n\n // NOTE: we might want to enforce this? Not sure\n // ensureConfirmationKeyMatchesDpopKey: true\n },\n dpop: {\n ...dpop,\n // First session config, fall back to global config\n required: issuanceSession.dpop?.required ?? config.dpopRequired,\n },\n expectedTxCode: issuanceSession.userPin,\n preAuthorizedCodeExpiresAt:\n issuanceSession.expiresAt ??\n utils.addSecondsToDate(issuanceSession.createdAt, config.statefulCredentialOfferExpirationInSeconds),\n })\n } else if (grant.grantType === authorizationCodeGrantIdentifier) {\n if (!issuanceSession.authorization?.code || !issuanceSession.authorization?.codeExpiresAt) {\n throw new Oauth2ServerErrorResponseError(\n {\n error: Oauth2ErrorCodes.InvalidGrant,\n error_description: 'Invalid authorization code',\n },\n {\n internalMessage:\n 'Found issuance session without authorization.code or authorization.codeExpiresAt. This should not happen as the issuance session is fetched based on the authorization code',\n }\n )\n }\n verificationResult = await oauth2AuthorizationServer.verifyAuthorizationCodeAccessTokenRequest({\n accessTokenRequest,\n expectedCode: issuanceSession.authorization.code,\n codeExpiresAt: issuanceSession.authorization.codeExpiresAt,\n grant,\n authorizationServerMetadata: issuerMetadata.authorizationServers[0],\n request: requestLike,\n clientAttestation: {\n ...clientAttestation,\n\n // Ensure it matches the previously provided client id\n // FIXME: we don't verify that the attestation is issued by the same party\n expectedClientId: issuanceSession.clientId,\n\n // NOTE: we don't look at the global config here. As we already checked and\n // set required to true previously if client attestations were provided or required.\n required: issuanceSession.walletAttestation?.required,\n\n // NOTE: we might want to enforce this? Not sure\n // ensureConfirmationKeyMatchesDpopKey: true\n },\n dpop: {\n ...dpop,\n // NOTE: we don't look at the global config here. As we already checked and\n // set required to true previously if client attestations were provided or required.\n required: issuanceSession.dpop?.required,\n\n // Ensure it matches previously provided jwk thumbprint\n expectedJwkThumbprint: issuanceSession.dpop?.dpopJkt,\n },\n pkce: issuanceSession.pkce\n ? {\n codeChallenge: issuanceSession.pkce.codeChallenge,\n codeChallengeMethod: issuanceSession.pkce.codeChallengeMethod,\n codeVerifier: pkceCodeVerifier,\n }\n : undefined,\n })\n } else if (grant.grantType === refreshTokenGrantIdentifier) {\n if (!parsedRefreshToken) {\n throw new CredoError('Refresh token verification is required for refresh token grant type')\n }\n\n verificationResult = await oauth2AuthorizationServer.verifyRefreshTokenAccessTokenRequest({\n accessTokenRequest,\n // Refresh token validity is already checked before\n expectedRefreshToken: grant.refreshToken,\n grant,\n request: requestLike,\n authorizationServerMetadata: issuerMetadata.authorizationServers[0],\n clientAttestation: {\n ...clientAttestation,\n // First session config, fall back to global config\n required: issuanceSession.walletAttestation?.required ?? config.walletAttestationsRequired,\n\n // NOTE: we might want to enforce this? Not sure\n // ensureConfirmationKeyMatchesDpopKey: true\n },\n dpop: {\n ...dpop,\n // First session config, fall back to global config\n required: issuanceSession.dpop?.required ?? config.dpopRequired,\n },\n refreshTokenExpiresAt: parsedRefreshToken?.expiresAt,\n })\n\n await openId4VcIssuerService.verifyRefreshToken(agentContext, issuer, parsedRefreshToken, {\n dpop: verificationResult.dpop,\n })\n } else {\n throw new Oauth2ServerErrorResponseError({\n error: Oauth2ErrorCodes.UnsupportedGrantType,\n error_description: 'Unsupported grant type',\n })\n }\n\n // Do not update the session state if the grant type is refresh token. This\n // avoids the session state going \"backwards\".\n if (grant.grantType !== refreshTokenGrantIdentifier) {\n await openId4VcIssuerService.updateState(\n agentContext,\n issuanceSession,\n OpenId4VcIssuanceSessionState.AccessTokenRequested\n )\n }\n\n const { cNonce, cNonceExpiresInSeconds } = await openId4VcIssuerService.createNonce(agentContext, issuer)\n\n // for authorization code flow we take the authorization scopes. For pre-auth we don't use scopes (we just\n // use the offered credential configuration ids so a scope is not required)\n const scopes =\n grant.grantType === authorizationCodeGrantIdentifier ? issuanceSession.authorization?.scopes : undefined\n const subject = `credo:${utils.uuid()}`\n\n const tokenDpop = verificationResult.dpop\n ? {\n jwk: verificationResult.dpop?.jwk,\n }\n : undefined\n\n // Generate a refresh token if they're enabled in the config and the grant type is not refresh token\n let refreshToken: string | undefined\n if (issuanceSession.generateRefreshTokens && grant.grantType !== refreshTokenGrantIdentifier) {\n refreshToken = await openId4VcIssuerService.createRefreshToken(agentContext, issuer, {\n preAuthorizedCode: grant.grantType === preAuthorizedCodeGrantIdentifier ? grant.preAuthorizedCode : undefined,\n issuerState: issuanceSession.authorization?.issuerState,\n dpop: tokenDpop,\n })\n }\n\n const signerJwk = accessTokenSigningKey\n const accessTokenResponse = await oauth2AuthorizationServer.createAccessTokenResponse({\n audience: issuerMetadata.credentialIssuer.credential_issuer,\n authorizationServer: issuerMetadata.credentialIssuer.credential_issuer,\n expiresInSeconds: config.accessTokenExpiresInSeconds,\n signer: {\n method: 'jwk',\n alg: signerJwk.supportedSignatureAlgorithms[0],\n publicJwk: signerJwk.toJson() as Jwk,\n },\n dpop: tokenDpop,\n scope: scopes?.join(' '),\n clientId: issuanceSession.clientId,\n\n additionalAccessTokenPayload: {\n 'pre-authorized_code':\n grant.grantType === preAuthorizedCodeGrantIdentifier\n ? grant.preAuthorizedCode\n : parsedRefreshToken?.preAuthorizedCode,\n issuer_state: issuanceSession.authorization?.issuerState,\n },\n // We generate a random subject for each access token and bind the issuance session to this.\n subject,\n\n refreshToken,\n\n // NOTE: these have been removed in newer drafts. Keeping them in for now\n cNonce,\n cNonceExpiresIn: cNonceExpiresInSeconds,\n })\n\n issuanceSession.authorization = {\n ...issuanceSession.authorization,\n subject,\n }\n\n await openId4VcIssuerService.updateState(\n agentContext,\n issuanceSession,\n // Retain the current session state when refreshing the access token.\n grant.grantType === refreshTokenGrantIdentifier\n ? issuanceSession.state\n : OpenId4VcIssuanceSessionState.AccessTokenCreated\n )\n\n return sendJsonResponse(response, next, accessTokenResponse)\n } catch (error) {\n if (error instanceof Oauth2ServerErrorResponseError) {\n return sendOauth2ErrorResponse(response, next, agentContext.config.logger, error)\n }\n\n return sendUnknownServerErrorResponse(response, next, agentContext.config.logger, error)\n }\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
".": "./build/index.mjs",
|
|
5
5
|
"./package.json": "./package.json"
|
|
6
6
|
},
|
|
7
|
-
"version": "0.6.2-alpha-
|
|
7
|
+
"version": "0.6.2-alpha-20251211125344",
|
|
8
8
|
"files": [
|
|
9
9
|
"build"
|
|
10
10
|
],
|
|
@@ -30,18 +30,18 @@
|
|
|
30
30
|
"class-transformer": "0.5.1",
|
|
31
31
|
"rxjs": "^7.8.2",
|
|
32
32
|
"zod": "^4.1.12",
|
|
33
|
-
"@openid4vc/openid4vci": "^0.4.
|
|
34
|
-
"@openid4vc/oauth2": "^0.4.
|
|
35
|
-
"@openid4vc/openid4vp": "^0.4.
|
|
36
|
-
"@openid4vc/utils": "^0.4.
|
|
33
|
+
"@openid4vc/openid4vci": "^0.4.3",
|
|
34
|
+
"@openid4vc/oauth2": "^0.4.3",
|
|
35
|
+
"@openid4vc/openid4vp": "^0.4.3",
|
|
36
|
+
"@openid4vc/utils": "^0.4.3",
|
|
37
37
|
"@types/express": "^5.0.6",
|
|
38
38
|
"express": "^5.2.0",
|
|
39
|
-
"@credo-ts/core": "0.6.2-alpha-
|
|
39
|
+
"@credo-ts/core": "0.6.2-alpha-20251211125344"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"nock": "^14.0.10",
|
|
43
43
|
"typescript": "~5.9.3",
|
|
44
|
-
"@credo-ts/tenants": "0.6.2-alpha-
|
|
44
|
+
"@credo-ts/tenants": "0.6.2-alpha-20251211125344"
|
|
45
45
|
},
|
|
46
46
|
"scripts": {
|
|
47
47
|
"build": "tsdown --config-loader unconfig"
|