{"version":3,"file":"authorizationEndpoint.mjs","names":[],"sources":["../../../src/openid4vc-verifier/router/authorizationEndpoint.ts"],"sourcesContent":["import { AgentContext, TypedArrayEncoder } from '@credo-ts/core'\nimport { decodeJwtHeader, Oauth2ErrorCodes, Oauth2ServerErrorResponseError } from '@openid4vc/oauth2'\n// FIXME: export parseOpenid4VpAuthorizationResponsePayload from openid4vp\nimport { zOpenid4vpAuthorizationResponse } from '@openid4vc/openid4vp'\nimport { ValidationError } from '@openid4vc/utils'\nimport type { NextFunction, Request, Response, Router } from 'express'\nimport {\n  getRequestContext,\n  sendErrorResponse,\n  sendJsonResponse,\n  sendOauth2ErrorResponse,\n  sendUnknownServerErrorResponse,\n} from '../../shared/router'\nimport { OpenId4VcVerifierModuleConfig } from '../OpenId4VcVerifierModuleConfig'\nimport { OpenId4VpVerifierService } from '../OpenId4VpVerifierService'\nimport {\n  OpenId4VcVerificationSessionRecord,\n  OpenId4VcVerificationSessionRepository,\n  OpenId4VcVerifierRecord,\n} from '../repository'\nimport type { OpenId4VcVerificationRequest } from './requestContext'\n\nexport function configureAuthorizationEndpoint(router: Router, config: OpenId4VcVerifierModuleConfig) {\n  router.post(config.authorizationEndpoint, async (request: OpenId4VcVerificationRequest, response: Response, next) => {\n    const { agentContext, verifier } = getRequestContext(request)\n    const openId4VcVerifierService = agentContext.dependencyManager.resolve(OpenId4VpVerifierService)\n\n    let authorizationResponseRedirectUri: string | undefined\n\n    try {\n      const result = await getVerificationSession(agentContext, request, response, next, verifier)\n\n      // Response already handled in the method\n      if (!result.success) return\n\n      authorizationResponseRedirectUri = result.verificationSession.authorizationResponseRedirectUri\n\n      const { verificationSession } = await openId4VcVerifierService.verifyAuthorizationResponse(agentContext, {\n        authorizationResponse: request.body,\n        verificationSession: result.verificationSession,\n      })\n\n      return sendJsonResponse(response, next, {\n        // Used only for presentation during issuance flow, to prevent session fixation.\n        presentation_during_issuance_session: verificationSession.presentationDuringIssuanceSession,\n\n        redirect_uri: verificationSession.authorizationResponseRedirectUri,\n      })\n    } catch (error) {\n      if (error instanceof Oauth2ServerErrorResponseError) {\n        error.errorResponse.redirect_uri = authorizationResponseRedirectUri\n        return sendOauth2ErrorResponse(response, next, agentContext.config.logger, error)\n      }\n\n      // FIXME: should throw a Oauth2ServerErrorResponseError in the oid4vp library\n      if (error instanceof ValidationError) {\n        return sendOauth2ErrorResponse(\n          response,\n          next,\n          agentContext.config.logger,\n          new Oauth2ServerErrorResponseError(\n            {\n              error: Oauth2ErrorCodes.InvalidRequest,\n              error_description: error.message,\n              redirect_uri: authorizationResponseRedirectUri,\n            },\n            { cause: error }\n          )\n        )\n      }\n\n      return sendUnknownServerErrorResponse(response, next, agentContext.config.logger, error, {\n        redirect_uri: authorizationResponseRedirectUri,\n      })\n    }\n  })\n}\n\nasync function getVerificationSession(\n  agentContext: AgentContext,\n  request: Request,\n  response: Response,\n  next: NextFunction,\n  verifier: OpenId4VcVerifierRecord\n): Promise<{ success: true; verificationSession: OpenId4VcVerificationSessionRecord } | { success: false }> {\n  const openId4VcVerificationSessionRepository = agentContext.dependencyManager.resolve(\n    OpenId4VcVerificationSessionRepository\n  )\n\n  try {\n    if (request.query.session) {\n      if (typeof request.query.session !== 'string') {\n        sendErrorResponse(\n          response,\n          next,\n          agentContext.config.logger,\n          400,\n          Oauth2ErrorCodes.InvalidRequest,\n          `Unexpected value for 'session' query param`\n        )\n        return { success: false }\n      }\n\n      const verificationSession = await openId4VcVerificationSessionRepository.findSingleByQuery(agentContext, {\n        verifierId: verifier.verifierId,\n        authorizationRequestId: request.query.session,\n      })\n\n      if (!verificationSession) {\n        sendErrorResponse(\n          response,\n          next,\n          agentContext.config.logger,\n          400,\n          Oauth2ErrorCodes.InvalidRequest,\n          `Invalid 'session' parameter`\n        )\n        return { success: false }\n      }\n\n      return { success: true, verificationSession }\n    }\n\n    const parsedResponse = zOpenid4vpAuthorizationResponse.safeParse(request.body)\n    if (parsedResponse.success) {\n      if (!parsedResponse.data.state) {\n        sendErrorResponse(\n          response,\n          next,\n          agentContext.config.logger,\n          400,\n          Oauth2ErrorCodes.InvalidRequest,\n          `Missing required 'state' parameter in response without response encryption`\n        )\n        return { success: false }\n      }\n\n      const verificationSession = await openId4VcVerificationSessionRepository.findSingleByQuery(agentContext, {\n        payloadState: parsedResponse.data.state,\n        verifierId: verifier.verifierId,\n      })\n\n      if (!verificationSession) {\n        sendErrorResponse(\n          response,\n          next,\n          agentContext.config.logger,\n          400,\n          Oauth2ErrorCodes.InvalidRequest,\n          `Invalid 'state' parameter`\n        )\n        return { success: false }\n      }\n\n      return { success: true, verificationSession }\n    }\n\n    // Try extracting apv (request nonce), which is used in encrypted responses (for ISO 18013-7/before draft 24)\n    if (typeof request.body === 'object' && 'response' in request.body) {\n      const { header } = decodeJwtHeader({\n        jwt: request.body.response,\n      })\n\n      if (!header.apv) {\n        sendErrorResponse(\n          response,\n          next,\n          agentContext.config.logger,\n          400,\n          Oauth2ErrorCodes.InvalidRequest,\n          `Missing 'session' query param or 'apv' value in header of encrypted JARM response.`\n        )\n        return { success: false }\n      }\n\n      if (typeof header.apv !== 'string') {\n        sendErrorResponse(\n          response,\n          next,\n          agentContext.config.logger,\n          400,\n          Oauth2ErrorCodes.InvalidRequest,\n          `'apv' value in header of encrypted JARM response is not of type string.`\n        )\n        return { success: false }\n      }\n\n      const nonce = TypedArrayEncoder.toUtf8String(TypedArrayEncoder.fromBase64Url(header.apv))\n      const verificationSession = await openId4VcVerificationSessionRepository.findSingleByQuery(agentContext, {\n        nonce,\n        verifierId: verifier.verifierId,\n      })\n\n      if (!verificationSession) {\n        sendErrorResponse(\n          response,\n          next,\n          agentContext.config.logger,\n          400,\n          Oauth2ErrorCodes.InvalidRequest,\n          `Invalid 'apv' parameter`\n        )\n        return { success: false }\n      }\n\n      return { success: true, verificationSession }\n    }\n\n    sendErrorResponse(\n      response,\n      next,\n      agentContext.config.logger,\n      400,\n      Oauth2ErrorCodes.InvalidRequest,\n      'Invalid response'\n    )\n    return { success: false }\n  } catch (error) {\n    sendUnknownServerErrorResponse(response, next, agentContext.config.logger, error)\n    return { success: false }\n  }\n}\n"],"mappings":"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"}