diff --git a/apps/agent-service/src/agent-service.controller.ts b/apps/agent-service/src/agent-service.controller.ts index 31d375603e..9024f06e85 100644 --- a/apps/agent-service/src/agent-service.controller.ts +++ b/apps/agent-service/src/agent-service.controller.ts @@ -18,7 +18,8 @@ import { ITenantRecord, ITenantSchema, IUserRequestInterface, - IWallet + IWallet, + VerifyAuthorizationResponse } from './interface/agent-service.interface'; import { AgentServiceService } from './agent-service.service'; @@ -467,4 +468,20 @@ export class AgentServiceController { ); return this.agentServiceService.createOid4vpVerificationSession(payload.sessionRequest, payload.url, payload.orgId); } + + @MessagePattern({ cmd: 'agent-verify-oid4vp-session-auth-response' }) + async verifyOid4vpSessionAuthResponse(payload: { + verifyAuthorizationResponse: VerifyAuthorizationResponse; + url: string; + orgId: string; + }): Promise { + this.logger.log( + `[verifyOid4vpSessionAuthResponse] Received 'agent-verify-oid4vp-session-auth-response' request for orgId=${payload?.orgId || 'N/A'}` + ); + return this.agentServiceService.verifyOid4vpSessionAuthResponse( + payload.verifyAuthorizationResponse, + payload.url, + payload.orgId + ); + } } diff --git a/apps/agent-service/src/agent-service.service.ts b/apps/agent-service/src/agent-service.service.ts index f5e28d9314..19aec908bc 100644 --- a/apps/agent-service/src/agent-service.service.ts +++ b/apps/agent-service/src/agent-service.service.ts @@ -54,7 +54,8 @@ import { IBasicMessage, WalletDetails, ILedger, - IStoreOrgAgent + IStoreOrgAgent, + VerifyAuthorizationResponse } from './interface/agent-service.interface'; import { AgentSpinUpStatus, AgentType, DidMethod, Ledgers, OrgAgentType, PromiseResult } from '@credebl/enum/enum'; import { AgentServiceRepository } from './repositories/agent-service.repository'; @@ -2284,4 +2285,26 @@ export class AgentServiceService { throw error; } } + + async verifyOid4vpSessionAuthResponse( + verifyAuthorizationResponse: VerifyAuthorizationResponse, + url: string, + orgId: string + ): Promise { + this.logger.log( + `[verifyOid4vpSessionAuthResponse] Verifying OID4VP session auth response for orgId=${orgId || 'N/A'}` + ); + try { + const getApiKey = await this.getOrgAgentApiKey(orgId); + const verifySession = await this.commonService + .httpPost(url, verifyAuthorizationResponse, { headers: { authorization: getApiKey } }) + .then(async (response) => response); + return verifySession; + } catch (error) { + this.logger.error( + `[verifyOid4vpSessionAuthResponse] Error in verifying oid4vp session auth response in agent service : ${JSON.stringify(error)}` + ); + throw error; + } + } } diff --git a/apps/agent-service/src/interface/agent-service.interface.ts b/apps/agent-service/src/interface/agent-service.interface.ts index 8c4a601978..40580feec0 100644 --- a/apps/agent-service/src/interface/agent-service.interface.ts +++ b/apps/agent-service/src/interface/agent-service.interface.ts @@ -660,3 +660,9 @@ export interface WalletDetails { tenantId: string; orgId: string; } + +export interface VerifyAuthorizationResponse { + verificationSessionId: string; + authorizationResponse: Record; + origin?: string; +} diff --git a/apps/api-gateway/src/oid4vc-verification/dtos/verify-authorization-response.dto.ts b/apps/api-gateway/src/oid4vc-verification/dtos/verify-authorization-response.dto.ts new file mode 100644 index 0000000000..84132f9d12 --- /dev/null +++ b/apps/api-gateway/src/oid4vc-verification/dtos/verify-authorization-response.dto.ts @@ -0,0 +1,36 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { IsNotEmpty, IsObject, IsOptional, IsString } from 'class-validator'; + +export class VerifyAuthorizationResponseDto { + @ApiProperty({ + description: 'verification session id received in the authorization response', + example: '93e156ca-a6b9-46ea-913d-f499be167d02' + }) + @IsString() + @IsNotEmpty() + verificationSessionId!: string; + + @ApiProperty({ + description: + 'authorization response received from the wallet after user approves or denies the verification request', + example: { + // eslint-disable-next-line camelcase + id_token: { + Passport: [ + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2V4YW1wbGUuY29tL2F1dGgvdjEvcmVhbG0tY3JlZGVibCIsInN1YiI6IjEyMzQ1Njc4OTAiLCJhdWQiOiJhdXRoLWNlbnRlci1pZCIsImV4cCI6MTY5ODAwMDAwMCwiaWF0IjoxNjk3OTk2NDAwfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c' + ] + } + } + }) + @IsObject() + @IsNotEmpty() + authorizationResponse!: Record; + + @ApiProperty({ + description: 'The origin of the verification session, if Digital Credentials API was used.', + example: 'https://example.com' + }) + @IsOptional() + @IsString() + origin?: string; +} diff --git a/apps/api-gateway/src/oid4vc-verification/oid4vc-verification.controller.ts b/apps/api-gateway/src/oid4vc-verification/oid4vc-verification.controller.ts index 126d337be9..66e25088f0 100644 --- a/apps/api-gateway/src/oid4vc-verification/oid4vc-verification.controller.ts +++ b/apps/api-gateway/src/oid4vc-verification/oid4vc-verification.controller.ts @@ -50,6 +50,7 @@ import { PresentationRequestDto, VerificationPresentationQueryDto } from './dtos import { Oid4vpPresentationWhDto } from '../oid4vc-issuance/dtos/oid4vp-presentation-wh.dto'; import { CreateVerificationTemplateDto, UpdateVerificationTemplateDto } from './dtos/verification-template.dto'; import { CreateIntentBasedVerificationDto } from './dtos/create-intent-based-verification.dto'; +import { VerifyAuthorizationResponseDto } from './dtos/verify-authorization-response.dto'; @Controller() @UseFilters(CustomExceptionFilter) @@ -718,4 +719,45 @@ export class Oid4vcVerificationController { }; return res.status(HttpStatus.OK).json(finalResponse); } + + @Post('/orgs/:orgId/oid4vp/verify-authorization-response') + @ApiOperation({ + summary: 'Verify authorization response', + description: 'Verifies an authorization response for the specified organization.' + }) + @ApiResponse({ + status: HttpStatus.OK, + description: 'Authorization response verified successfully.', + type: ApiResponseDto + }) + @ApiBearerAuth() + @Roles(OrgRoles.OWNER) + @UseGuards(AuthGuard('jwt'), OrgRolesGuard) + async verifyAuthorizationResponse( + @Param( + 'orgId', + new ParseUUIDPipe({ + exceptionFactory: (): Error => { + throw new BadRequestException(ResponseMessages.organisation.error.invalidOrgId); + } + }) + ) + orgId: string, + @Body() verifyAuthorizationResponseDto: VerifyAuthorizationResponseDto, + @Res() res: Response + ): Promise { + this.logger.debug(`[verifyAuthorizationResponse] Called with orgId=${orgId}`); + + const result = await this.oid4vcVerificationService.verifyAuthorizationResponse( + verifyAuthorizationResponseDto, + orgId + ); + this.logger.debug(`[verifyAuthorizationResponse] Authorization response verified successfully for orgId=${orgId}`); + const finalResponse: IResponse = { + statusCode: HttpStatus.CREATED, + message: 'Authorization response verified successfully', + data: result + }; + return res.status(HttpStatus.CREATED).json(finalResponse); + } } diff --git a/apps/api-gateway/src/oid4vc-verification/oid4vc-verification.service.ts b/apps/api-gateway/src/oid4vc-verification/oid4vc-verification.service.ts index 90c44d14b2..3f438b1835 100644 --- a/apps/api-gateway/src/oid4vc-verification/oid4vc-verification.service.ts +++ b/apps/api-gateway/src/oid4vc-verification/oid4vc-verification.service.ts @@ -9,6 +9,7 @@ import { IPresentationRequest } from '@credebl/common/interfaces/oid4vp-verifica import { Oid4vpPresentationWhDto } from '../oid4vc-issuance/dtos/oid4vp-presentation-wh.dto'; import { CreateVerificationTemplateDto, UpdateVerificationTemplateDto } from './dtos/verification-template.dto'; import { CreateIntentBasedVerificationDto } from './dtos/create-intent-based-verification.dto'; +import { VerifyAuthorizationResponseDto } from './dtos/verify-authorization-response.dto'; @Injectable() export class Oid4vcVerificationService { @@ -173,4 +174,12 @@ export class Oid4vcVerificationService { this.logger.debug(`[deleteVerificationTemplate] Called with orgId=${orgId}, templateId=${templateId}`); return this.natsClient.sendNatsMessage(this.oid4vpProxy, 'verification-template-delete', payload); } + async verifyAuthorizationResponse( + verifyAuthorizationResponse: VerifyAuthorizationResponseDto, + orgId: string + ): Promise { + const payload = { verifyAuthorizationResponse, orgId }; + this.logger.debug(`[verifyAuthorizationResponse] Called with orgId=${orgId}`); + return this.natsClient.sendNatsMessage(this.oid4vpProxy, 'verify-authorization-response', payload); + } } diff --git a/apps/oid4vc-verification/interfaces/oid4vp-verification-sessions.interfaces.ts b/apps/oid4vc-verification/interfaces/oid4vp-verification-sessions.interfaces.ts index 974b039864..f949c68a78 100644 --- a/apps/oid4vc-verification/interfaces/oid4vp-verification-sessions.interfaces.ts +++ b/apps/oid4vc-verification/interfaces/oid4vp-verification-sessions.interfaces.ts @@ -23,3 +23,9 @@ export interface X5cSigner { } export type RequestSigner = DidSigner | X5cSigner; + +export interface VerifyAuthorizationResponse { + verificationSessionId: string; + authorizationResponse: Record; + origin?: string; +} diff --git a/apps/oid4vc-verification/src/oid4vc-verification.controller.ts b/apps/oid4vc-verification/src/oid4vc-verification.controller.ts index 52ae1ee7d9..a27615906b 100644 --- a/apps/oid4vc-verification/src/oid4vc-verification.controller.ts +++ b/apps/oid4vc-verification/src/oid4vc-verification.controller.ts @@ -9,7 +9,10 @@ import { } from '@credebl/common/interfaces/oid4vp-verification'; import { MessagePattern } from '@nestjs/microservices'; import { VerificationSessionQuery } from '../interfaces/oid4vp-verifier.interfaces'; -import { Oid4vpPresentationWh } from '../interfaces/oid4vp-verification-sessions.interfaces'; +import { + Oid4vpPresentationWh, + VerifyAuthorizationResponse +} from '../interfaces/oid4vp-verification-sessions.interfaces'; import { CreateVerificationTemplate, UpdateVerificationTemplate } from '../interfaces/verification-template.interfaces'; @Controller() @@ -181,4 +184,16 @@ export class Oid4vpVerificationController { ); return this.oid4vpVerificationService.deleteVerificationTemplate(orgId, templateId); } + + @MessagePattern({ cmd: 'verify-authorization-response' }) + async verifyAuthorizationResponse(payload: { + verifyAuthorizationResponse: VerifyAuthorizationResponse; + orgId: string; + }): Promise { + const { verifyAuthorizationResponse, orgId } = payload; + this.logger.debug( + `[verifyAuthorizationResponse] Received 'verify-authorization-response' request for orgId=${orgId}` + ); + return this.oid4vpVerificationService.verifyAuthorizationResponse(verifyAuthorizationResponse, orgId); + } } diff --git a/apps/oid4vc-verification/src/oid4vc-verification.service.ts b/apps/oid4vc-verification/src/oid4vc-verification.service.ts index 3c8862d199..666b242f92 100644 --- a/apps/oid4vc-verification/src/oid4vc-verification.service.ts +++ b/apps/oid4vc-verification/src/oid4vc-verification.service.ts @@ -32,7 +32,11 @@ import { VerificationSessionQuery } from '../interfaces/oid4vp-verifier.interfac import { BaseService } from 'libs/service/base.service'; import { NATSClient } from '@credebl/common/NATSClient'; -import { Oid4vpPresentationWh, RequestSigner } from '../interfaces/oid4vp-verification-sessions.interfaces'; +import { + Oid4vpPresentationWh, + RequestSigner, + VerifyAuthorizationResponse +} from '../interfaces/oid4vp-verification-sessions.interfaces'; import { X509CertificateRecord } from '@credebl/common/interfaces/x509.interface'; import { SignerMethodOption, x5cKeyType } from '@credebl/enum/enum'; import { CreateVerificationTemplate, UpdateVerificationTemplate } from '../interfaces/verification-template.interfaces'; @@ -694,4 +698,31 @@ export class Oid4vpVerificationService extends BaseService { throw new RpcException(error?.response ?? error.error ?? error); } } + + async verifyAuthorizationResponse( + verifyAuthorizationResponse: VerifyAuthorizationResponse, + orgId: string + ): Promise { + this.logger.debug( + `[verifyAuthorizationResponse] called for orgId=${orgId}, verificationSessionId=${JSON.stringify(verifyAuthorizationResponse.verificationSessionId)}` + ); + try { + const agentDetails = await this.oid4vpRepository.getAgentEndPoint(orgId); + if (!agentDetails) { + throw new NotFoundException(ResponseMessages.issuance.error.agentEndPointNotFound); + } + const { agentEndPoint, id } = agentDetails; + const url = getAgentUrl(agentEndPoint, CommonConstants.OIDC_VERIFIER_SESSION_AUTH_RESPONSE_VERIFY); + const verificationResult = await this.natsClient.sendNatsMessage( + this.oid4vpVerificationServiceProxy, + 'agent-verify-oid4vp-session-auth-response', + { url, orgId, verifyAuthorizationResponse } + ); + this.logger.debug(`[verifyAuthorizationResponse] verification result received successfully for orgId=${orgId}`); + return verificationResult; + } catch (error) { + this.logger.error(`[verifyAuthorizationResponse] - error: ${JSON.stringify(error)}`); + throw new RpcException(error?.response ?? error); + } + } } diff --git a/libs/common/src/common.constant.ts b/libs/common/src/common.constant.ts index 62d1f13221..d1cb0a52e2 100644 --- a/libs/common/src/common.constant.ts +++ b/libs/common/src/common.constant.ts @@ -135,6 +135,7 @@ export enum CommonConstants { URL_OIDC_VERIFIER_SESSION_GET_BY_QUERY = '/openid4vc/verification-sessions', URL_OIDC_VERIFIER_SESSION_RESPONSE_GET_BY_ID = '/openid4vc/verification-sessions/response/#', URL_OID4VP_VERIFICATION_SESSION = '/openid4vc/verification-sessions/create-presentation-request', + URL_OIDC_VERIFIER_SESSION_AUTH_RESPONSE_VERIFY = '/openid4vc/verification-sessions/verify-authorization-response', //X509 agent API URLs URL_CREATE_X509_CERTIFICATE = '/x509', @@ -439,6 +440,7 @@ export enum CommonConstants { OIDC_VERIFIER_SESSION_GET_BY_ID = 'get-oid4vp-verifier-session-id', OIDC_VERIFIER_SESSION_GET_BY_QUERY = 'get-oid4vp-verifier-session-query', OIDC_VERIFIER_SESSION_RESPONSE_GET_BY_ID = 'get-oid4vp-verifier-session-response-id', + OIDC_VERIFIER_SESSION_AUTH_RESPONSE_VERIFY = 'verify-oid4vp-verifier-session-auth-response', //X509 X509_CREATE_CERTIFICATE = 'create-x509-certificate', diff --git a/libs/common/src/common.utils.ts b/libs/common/src/common.utils.ts index 4e864d614a..6956e668eb 100644 --- a/libs/common/src/common.utils.ts +++ b/libs/common/src/common.utils.ts @@ -125,7 +125,11 @@ export const getAgentUrl = (agentEndPoint: string, urlFlag: string, paramId?: st String(CommonConstants.OIDC_VERIFIER_SESSION_RESPONSE_GET_BY_ID), String(CommonConstants.URL_OIDC_VERIFIER_SESSION_RESPONSE_GET_BY_ID) ], - [String(CommonConstants.OID4VP_VERIFICATION_SESSION), String(CommonConstants.URL_OID4VP_VERIFICATION_SESSION)] + [String(CommonConstants.OID4VP_VERIFICATION_SESSION), String(CommonConstants.URL_OID4VP_VERIFICATION_SESSION)], + [ + String(CommonConstants.OIDC_VERIFIER_SESSION_AUTH_RESPONSE_VERIFY), + String(CommonConstants.URL_OIDC_VERIFIER_SESSION_AUTH_RESPONSE_VERIFY) + ] ]); const urlSuffix = agentUrlMap.get(urlFlag);