@sphereon/ssi-sdk.siopv2-oid4vp-rp-rest-api 0.34.1-feature.DIIPv4.144 → 0.34.1-feature.DIIPv4.152

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sphereon/ssi-sdk.siopv2-oid4vp-rp-rest-api",
3
- "version": "0.34.1-feature.DIIPv4.144+a29ab83f",
3
+ "version": "0.34.1-feature.DIIPv4.152+83b31d2d",
4
4
  "source": "src/index.ts",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -23,16 +23,16 @@
23
23
  "start:dev": "ts-node __tests__/RestAPI.ts"
24
24
  },
25
25
  "dependencies": {
26
- "@sphereon/did-auth-siop": "0.19.1-feature.DIIPv4.106",
27
- "@sphereon/ssi-express-support": "0.34.1-feature.DIIPv4.144+a29ab83f",
28
- "@sphereon/ssi-sdk.core": "0.34.1-feature.DIIPv4.144+a29ab83f",
29
- "@sphereon/ssi-sdk.credential-validation": "0.34.1-feature.DIIPv4.144+a29ab83f",
30
- "@sphereon/ssi-sdk.kv-store-temp": "0.34.1-feature.DIIPv4.144+a29ab83f",
31
- "@sphereon/ssi-sdk.pd-manager": "0.34.1-feature.DIIPv4.144+a29ab83f",
32
- "@sphereon/ssi-sdk.presentation-exchange": "0.34.1-feature.DIIPv4.144+a29ab83f",
33
- "@sphereon/ssi-sdk.siopv2-oid4vp-common": "0.34.1-feature.DIIPv4.144+a29ab83f",
34
- "@sphereon/ssi-sdk.siopv2-oid4vp-rp-auth": "0.34.1-feature.DIIPv4.144+a29ab83f",
35
- "@sphereon/ssi-types": "0.34.1-feature.DIIPv4.144+a29ab83f",
26
+ "@sphereon/did-auth-siop": "0.19.1-feature.DIIPv4.126",
27
+ "@sphereon/ssi-express-support": "0.34.1-feature.DIIPv4.152+83b31d2d",
28
+ "@sphereon/ssi-sdk.core": "0.34.1-feature.DIIPv4.152+83b31d2d",
29
+ "@sphereon/ssi-sdk.credential-validation": "0.34.1-feature.DIIPv4.152+83b31d2d",
30
+ "@sphereon/ssi-sdk.kv-store-temp": "0.34.1-feature.DIIPv4.152+83b31d2d",
31
+ "@sphereon/ssi-sdk.pd-manager": "0.34.1-feature.DIIPv4.152+83b31d2d",
32
+ "@sphereon/ssi-sdk.presentation-exchange": "0.34.1-feature.DIIPv4.152+83b31d2d",
33
+ "@sphereon/ssi-sdk.siopv2-oid4vp-common": "0.34.1-feature.DIIPv4.152+83b31d2d",
34
+ "@sphereon/ssi-sdk.siopv2-oid4vp-rp-auth": "0.34.1-feature.DIIPv4.152+83b31d2d",
35
+ "@sphereon/ssi-types": "0.34.1-feature.DIIPv4.152+83b31d2d",
36
36
  "@veramo/core": "4.2.0",
37
37
  "@veramo/credential-w3c": "4.2.0",
38
38
  "awesome-qr": "^2.1.5-rc.0",
@@ -44,18 +44,21 @@
44
44
  "express": "^4.19.2",
45
45
  "short-uuid": "^4.2.2",
46
46
  "swagger-ui-express": "^5.0.1",
47
- "uuid": "^9.0.1"
47
+ "uuid": "^9.0.1",
48
+ "zod": "^4.1.5"
48
49
  },
49
50
  "devDependencies": {
50
51
  "@decentralized-identity/ion-sdk": "^0.6.0",
51
- "@sphereon/did-auth-siop-adapter": "0.19.1-feature.DIIPv4.106",
52
+ "@sphereon/did-auth-siop-adapter": "0.19.1-feature.DIIPv4.126",
52
53
  "@sphereon/did-uni-client": "^0.6.3",
53
54
  "@sphereon/pex": "5.0.0-unstable.28",
54
55
  "@sphereon/pex-models": "^2.3.2",
55
- "@sphereon/ssi-sdk-ext.did-provider-jwk": "0.34.1-feature.DIIPv4.144+a29ab83f",
56
- "@sphereon/ssi-sdk.credential-vcdm": "0.34.1-feature.DIIPv4.144+a29ab83f",
57
- "@sphereon/ssi-sdk.credential-vcdm-jsonld-provider": "0.34.1-feature.DIIPv4.144+a29ab83f",
58
- "@sphereon/ssi-sdk.data-store": "0.34.1-feature.DIIPv4.144+a29ab83f",
56
+ "@sphereon/ssi-sdk-ext.did-provider-jwk": "0.34.1-feature.DIIPv4.152+83b31d2d",
57
+ "@sphereon/ssi-sdk-ext.identifier-resolution": "0.34.1-feature.DIIPv4.152+83b31d2d",
58
+ "@sphereon/ssi-sdk-ext.jwt-service": "0.34.1-feature.DIIPv4.152+83b31d2d",
59
+ "@sphereon/ssi-sdk.credential-vcdm": "0.34.1-feature.DIIPv4.152+83b31d2d",
60
+ "@sphereon/ssi-sdk.credential-vcdm-jsonld-provider": "0.34.1-feature.DIIPv4.152+83b31d2d",
61
+ "@sphereon/ssi-sdk.data-store": "0.34.1-feature.DIIPv4.152+83b31d2d",
59
62
  "@types/body-parser": "^1.19.5",
60
63
  "@types/cookie-parser": "^1.4.7",
61
64
  "@types/cors": "^2.8.17",
@@ -114,5 +117,5 @@
114
117
  "OpenID Connect",
115
118
  "Authenticator"
116
119
  ],
117
- "gitHead": "a29ab83f56b42d27cb0b4eb9abbd15f457cca0c7"
120
+ "gitHead": "83b31d2d49f59a8a1709af00eba2312c2bd159a5"
118
121
  }
package/src/index.ts CHANGED
@@ -2,6 +2,6 @@
2
2
  * @public
3
3
  */
4
4
  export * from './siop-api-functions'
5
- export * from './webapp-api-functions'
5
+ export * from './universal-oid4vp-api-functions'
6
6
  export * from './types'
7
7
  export * from './siopv2-rp-api-server'
@@ -0,0 +1,20 @@
1
+ import { Request, Response, NextFunction } from 'express';
2
+ import { z, ZodError } from 'zod';
3
+
4
+ export const validateData = (schema: z.ZodObject<any, any>) => {
5
+ return (req: Request, res: Response, next: NextFunction) => {
6
+ try {
7
+ schema.parse(req.body);
8
+ next();
9
+ } catch (error) {
10
+ if (error instanceof ZodError) {
11
+ const errorMessages = error.issues.map((issue: any) => ({
12
+ message: `${issue.path.join('.')} is ${issue.message}`,
13
+ }))
14
+ res.status(400).json({ status: 400, message: 'Invalid data', error_details: errorMessages[0].message });
15
+ } else {
16
+ res.status(500).json({ status: 500, message: 'Internal Server Error' });
17
+ }
18
+ }
19
+ };
20
+ }
@@ -0,0 +1,51 @@
1
+ import { z } from 'zod';
2
+ import {
3
+ authorizationRequestStatuses,
4
+ authorizationResponseStatuses
5
+ } from '@sphereon/ssi-sdk.siopv2-oid4vp-common'
6
+ import { ResponseMode, ResponseType, RequestUriMethod } from '@sphereon/did-auth-siop'
7
+
8
+ export const ResponseTypeSchema = z.enum([ResponseType.VP_TOKEN]);
9
+
10
+ export const ResponseModeSchema = z.enum([ResponseMode.DIRECT_POST, ResponseMode.DIRECT_POST_JWT]);
11
+
12
+ const requestUriMethods = ["get", "post"] as const satisfies Array<RequestUriMethod>;
13
+ export const RequestUriMethodSchema = z.enum(requestUriMethods);
14
+
15
+ export const AuthorizationStatusSchema = z.enum([
16
+ ...authorizationRequestStatuses,
17
+ ...authorizationResponseStatuses
18
+ ]);
19
+
20
+ export const CallbackOptsSchema = z.object({
21
+ url: z.string(),
22
+ status: z.array(AuthorizationStatusSchema).optional(),
23
+ });
24
+
25
+ export const QRCodeOptsSchema = z.object({
26
+ size: z.number().optional(),
27
+ color_dark: z.string().optional(),
28
+ color_light: z.string().optional(),
29
+ });
30
+
31
+ export const CreateAuthorizationRequestBodySchema = z.object({
32
+ query_id: z.string(),
33
+ client_id: z.string().optional(),
34
+ request_uri_base: z.string().optional(),
35
+ correlation_id: z.string().optional(),
36
+ request_uri_method: RequestUriMethodSchema.optional(),
37
+ response_type: ResponseTypeSchema.optional(),
38
+ response_mode: ResponseModeSchema.optional(),
39
+ transaction_data: z.array(z.string()).optional(),
40
+ qr_code: QRCodeOptsSchema.optional(),
41
+ direct_post_response_redirect_uri: z.string().optional(),
42
+ callback: CallbackOptsSchema.optional(),
43
+ });
44
+
45
+ export const CreateAuthorizationResponseSchema = z.object({
46
+ correlation_id: z.string(),
47
+ query_id: z.string(),
48
+ request_uri: z.string(),
49
+ status_uri: z.string(),
50
+ qr_uri: z.string().optional(),
51
+ });
@@ -71,7 +71,6 @@ export function verifyAuthResponseSIOPv2Endpoint(router: Router, context: IRequi
71
71
  const verifiedResponse = await context.agent.siopVerifyAuthResponse({
72
72
  authorizationResponse,
73
73
  correlationId,
74
- definitionId,
75
74
  dcqlQueryPayload: definitionItem.dcqlPayload,
76
75
  })
77
76
 
@@ -89,7 +88,7 @@ export function verifyAuthResponseSIOPv2Endpoint(router: Router, context: IRequi
89
88
  return response.send(JSON.stringify(authorizationChallengeValidationResponse))
90
89
  }
91
90
 
92
- const responseRedirectURI = await context.agent.siopGetRedirectURI({ correlationId, definitionId, state: verifiedResponse.state })
91
+ const responseRedirectURI = await context.agent.siopGetRedirectURI({ correlationId, queryId: definitionId, state: verifiedResponse.state })
93
92
  if (responseRedirectURI) {
94
93
  response.setHeader('Content-Type', 'application/json')
95
94
  return response.send(JSON.stringify({ redirect_uri: responseRedirectURI }))
@@ -124,7 +123,7 @@ export function getAuthRequestSIOPv2Endpoint(router: Router, context: IRequiredC
124
123
  }
125
124
  const requestState = await context.agent.siopGetAuthRequestState({
126
125
  correlationId,
127
- definitionId,
126
+ queryId: definitionId,
128
127
  errorOnNotFound: false,
129
128
  })
130
129
  if (!requestState) {
@@ -148,8 +147,8 @@ export function getAuthRequestSIOPv2Endpoint(router: Router, context: IRequiredC
148
147
  } finally {
149
148
  await context.agent.siopUpdateAuthRequestState({
150
149
  correlationId,
151
- definitionId,
152
- state: 'sent',
150
+ queryId: definitionId,
151
+ state: 'authorization_request_created',
153
152
  error,
154
153
  })
155
154
  }
@@ -7,11 +7,11 @@ import express, { Express, Request, Response, Router } from 'express'
7
7
  import { getAuthRequestSIOPv2Endpoint, verifyAuthResponseSIOPv2Endpoint } from './siop-api-functions'
8
8
  import { IRequiredPlugins, ISIOPv2RPRestAPIOpts } from './types'
9
9
  import {
10
- authStatusWebappEndpoint,
11
- createAuthRequestWebappEndpoint,
10
+ authStatusUniversalOID4VPEndpoint,
11
+ createAuthRequestUniversalOID4VPEndpoint,
12
12
  getDefinitionsEndpoint,
13
- removeAuthRequestStateWebappEndpoint,
14
- } from './webapp-api-functions'
13
+ removeAuthRequestStateUniversalOID4VPEndpoint,
14
+ } from './universal-oid4vp-api-functions'
15
15
  import swaggerUi from 'swagger-ui-express'
16
16
 
17
17
  export class SIOPv2RPApiServer {
@@ -40,9 +40,9 @@ export class SIOPv2RPApiServer {
40
40
 
41
41
  // Webapp endpoints
42
42
  if (features.includes('rp-status')) {
43
- createAuthRequestWebappEndpoint(this._router, context, opts?.endpointOpts?.webappCreateAuthRequest)
44
- authStatusWebappEndpoint(this._router, context, opts?.endpointOpts?.webappAuthStatus)
45
- removeAuthRequestStateWebappEndpoint(this._router, context, opts?.endpointOpts?.webappDeleteAuthRequest)
43
+ createAuthRequestUniversalOID4VPEndpoint(this._router, context, opts?.endpointOpts?.webappCreateAuthRequest)
44
+ authStatusUniversalOID4VPEndpoint(this._router, context, opts?.endpointOpts?.webappAuthStatus)
45
+ removeAuthRequestStateUniversalOID4VPEndpoint(this._router, context, opts?.endpointOpts?.webappDeleteAuthRequest)
46
46
  getDefinitionsEndpoint(this._router, context, opts?.endpointOpts?.webappGetDefinitions)
47
47
  }
48
48
 
@@ -1,11 +1,17 @@
1
+ import { IAgentContext, ICredentialVerifier } from '@veramo/core'
1
2
  import { GenericAuthArgs, ISingleEndpointOpts } from '@sphereon/ssi-express-support'
2
3
  import { IPresentationExchange } from '@sphereon/ssi-sdk.presentation-exchange'
3
4
  import { ISIOPv2RP } from '@sphereon/ssi-sdk.siopv2-oid4vp-rp-auth'
4
- import { IAgentContext, ICredentialVerifier } from '@veramo/core'
5
5
  import { IPDManager } from '@sphereon/ssi-sdk.pd-manager'
6
+ import { AdditionalClaims } from '@sphereon/ssi-types'
7
+ import { AuthorizationRequestStateStatus, AuthorizationResponseStateStatus } from '@sphereon/ssi-sdk.siopv2-oid4vp-common'
8
+ import { Request, Response } from 'express'
9
+ import { z } from 'zod'
10
+ import { CreateAuthorizationRequestBodySchema, CreateAuthorizationResponseSchema } from '../schemas'
6
11
  import { QRCodeOpts } from './QRCode.types'
7
12
 
8
13
  export type SiopFeatures = 'rp-status' | 'siop'
14
+
9
15
  export interface ISIOPv2RPRestAPIOpts {
10
16
  enableFeatures?: SiopFeatures[]
11
17
  endpointOpts?: {
@@ -30,3 +36,64 @@ export interface ICreateAuthRequestWebappEndpointOpts extends ISingleEndpointOpt
30
36
 
31
37
  export type IRequiredPlugins = ICredentialVerifier & ISIOPv2RP & IPresentationExchange & IPDManager
32
38
  export type IRequiredContext = IAgentContext<IRequiredPlugins>
39
+
40
+ export type CreateAuthorizationRequest = Request<Record<string, never>, any, CreateAuthorizationRequestBody, Record<string, never>>
41
+
42
+ export type CreateAuthorizationRequestBody = z.infer<typeof CreateAuthorizationRequestBodySchema>;
43
+
44
+ export type CreateAuthorizationResponse = Response<CreateAuthorizationRequestResponse>
45
+
46
+ export type CreateAuthorizationRequestResponse = z.infer<typeof CreateAuthorizationResponseSchema>;
47
+
48
+ export type DeleteAuthorizationRequest = Request<DeleteAuthorizationRequestPathParameters, any, Record<string, any>, Record<string, any>>
49
+
50
+ export type DeleteAuthorizationRequestPathParameters = {
51
+ correlationId: string;
52
+ }
53
+
54
+ export type GetAuthorizationRequestStatus = Request<GetAuthorizationRequestStatusPathParameters, any, Record<string, any>, Record<string, any>>
55
+
56
+ export type GetAuthorizationRequestStatusPathParameters = {
57
+ correlationId: string;
58
+ }
59
+
60
+ export type RequestError = {
61
+ status: number
62
+ message: string
63
+ error_details?: string
64
+ }
65
+
66
+ export type GetAuthStatusResponse = {
67
+ status: AuthorizationRequestStateStatus | AuthorizationResponseStateStatus
68
+ correlation_id: string
69
+ query_id: string
70
+ last_updated: number
71
+ verified_data?: VerifiedData
72
+ error?: RequestError
73
+ }
74
+
75
+ export type VerifiedData = {
76
+ authorization_response?: AuthorizationResponse
77
+ credential_claims?: AdditionalClaims
78
+ }
79
+
80
+ export type AuthorizationResponse = {
81
+ presentation_submission?: Record<string, any>
82
+ vp_token?: VpToken
83
+ }
84
+
85
+ export type SingleObjectVpTokenPE = Record<string, any>
86
+
87
+ export type SingleStringVpTokenPE = string
88
+
89
+ export type MultipleVpTokens = Array<SingleObjectVpTokenPE> | Array<SingleStringVpTokenPE>
90
+
91
+ export type MultipleVpTokenDCQL = {
92
+ [key: string]: MultipleVpTokens
93
+ }
94
+
95
+ export type VpToken =
96
+ | SingleObjectVpTokenPE
97
+ | SingleStringVpTokenPE
98
+ | MultipleVpTokens
99
+ | MultipleVpTokenDCQL
@@ -0,0 +1,171 @@
1
+ import { AuthorizationResponseStateStatus } from '@sphereon/did-auth-siop'
2
+ import { checkAuth, ISingleEndpointOpts, sendErrorResponse } from '@sphereon/ssi-express-support'
3
+ import { uriWithBase } from '@sphereon/ssi-sdk.siopv2-oid4vp-common'
4
+ import { Request, Response, Router } from 'express'
5
+ import uuid from 'short-uuid'
6
+ import { validateData } from './middleware/validationMiddleware'
7
+ import { CreateAuthorizationRequestBodySchema } from './schemas'
8
+ import {
9
+ CreateAuthorizationRequest,
10
+ CreateAuthorizationRequestResponse,
11
+ CreateAuthorizationResponse,
12
+ DeleteAuthorizationRequest,
13
+ GetAuthorizationRequestStatus,
14
+ GetAuthStatusResponse,
15
+ ICreateAuthRequestWebappEndpointOpts,
16
+ IRequiredContext
17
+ } from './types'
18
+
19
+ export function createAuthRequestUniversalOID4VPEndpoint(router: Router, context: IRequiredContext, opts?: ICreateAuthRequestWebappEndpointOpts) {
20
+ if (opts?.enabled === false) {
21
+ console.log(`createAuthRequest universal OID4VP endpoint is disabled`)
22
+ return
23
+ }
24
+
25
+ const path = opts?.path ?? '/backend/auth/requests'
26
+ router.post(path, checkAuth(opts?.endpoint), validateData(CreateAuthorizationRequestBodySchema), async (request: CreateAuthorizationRequest, response: CreateAuthorizationResponse) => {
27
+ try {
28
+ const correlationId = request.body.correlation_id ?? uuid.uuid()
29
+ const qrCodeOpts = request.body.qr_code ?? opts?.qrCodeOpts
30
+ const queryId = request.body.query_id
31
+ const directPostResponseRedirectUri = request.body.direct_post_response_redirect_uri // TODO Uri not URI
32
+ const requestUriBase = request.body.request_uri_base
33
+
34
+ const definitionItems = await context.agent.pdmGetDefinitions({ filter: [{ definitionId: queryId }] })
35
+ if (definitionItems.length === 0) {
36
+ console.log(`No query could be found for the given id. Query id: ${queryId}`)
37
+ return sendErrorResponse(response, 404, { status: 404, message: 'No query could be found' })
38
+ }
39
+
40
+ const requestByReferenceURI = uriWithBase(`/siop/definitions/${queryId}/auth-requests/${correlationId}`, {
41
+ baseURI: requestUriBase ?? opts?.siopBaseURI,
42
+ })
43
+ const responseURI = uriWithBase(`/siop/definitions/${queryId}/auth-responses/${correlationId}`, { baseURI: opts?.siopBaseURI })
44
+
45
+ const authRequestURI = await context.agent.siopCreateAuthRequestURI({
46
+ queryId,
47
+ correlationId,
48
+ nonce: uuid.uuid(),
49
+ requestByReferenceURI,
50
+ responseURIType: 'response_uri',
51
+ responseURI,
52
+ ...(directPostResponseRedirectUri && { responseRedirectURI: directPostResponseRedirectUri }),
53
+ })
54
+
55
+ let qrCodeDataUri: string | undefined
56
+ if (qrCodeOpts) {
57
+ const { AwesomeQR } = await import('awesome-qr')
58
+ const qrCode = new AwesomeQR({ ...qrCodeOpts, text: authRequestURI })
59
+ qrCodeDataUri = `data:image/png;base64,${(await qrCode.draw())!.toString('base64')}`
60
+ }
61
+
62
+ const authRequestBody = {
63
+ query_id: queryId,
64
+ correlation_id: correlationId,
65
+ request_uri: authRequestURI,
66
+ status_uri: `${uriWithBase(opts?.webappAuthStatusPath ?? `/backend/auth/status/${correlationId}`, { baseURI: opts?.webappBaseURI })}`,
67
+ ...(qrCodeDataUri && { qr_uri: qrCodeDataUri }),
68
+ } satisfies CreateAuthorizationRequestResponse
69
+ console.log(`Auth Request URI data to send back: ${JSON.stringify(authRequestBody)}`)
70
+
71
+ return response.status(201).json(authRequestBody)
72
+ } catch (error) {
73
+ return sendErrorResponse(response, 500, { status: 500, message: 'Could not create an authorization request URI' }, error)
74
+ }
75
+ })
76
+ }
77
+
78
+ export function removeAuthRequestStateUniversalOID4VPEndpoint(router: Router, context: IRequiredContext, opts?: ISingleEndpointOpts) {
79
+ if (opts?.enabled === false) {
80
+ console.log(`removeAuthStatus universal OID4VP endpoint is disabled`)
81
+ return
82
+ }
83
+
84
+ const path = opts?.path ?? '/backend/auth/requests/:correlationId'
85
+ router.delete(path, checkAuth(opts?.endpoint), async (request: DeleteAuthorizationRequest, response: Response) => {
86
+ try {
87
+ const correlationId: string = request.params.correlationId
88
+
89
+ const authRequestState = await context.agent.siopGetAuthRequestState({
90
+ correlationId,
91
+ errorOnNotFound: false
92
+ })
93
+ if (!authRequestState) {
94
+ console.log(`No authorization request could be found for the given correlationId. correlationId: ${correlationId}`)
95
+ return sendErrorResponse(response, 404, { status: 404, message: 'No authorization request could be found' })
96
+ }
97
+
98
+ await context.agent.siopDeleteAuthState({ correlationId })
99
+
100
+ return response.status(204).json()
101
+ } catch (error) {
102
+ return sendErrorResponse(response, 500, { status: 500, message: error.message }, error)
103
+ }
104
+ })
105
+ }
106
+
107
+ export function authStatusUniversalOID4VPEndpoint(router: Router, context: IRequiredContext, opts?: ISingleEndpointOpts) {
108
+ if (opts?.enabled === false) {
109
+ console.log(`authStatus universal OID4VP endpoint is disabled`)
110
+ return
111
+ }
112
+
113
+ const path = opts?.path ?? '/backend/auth/status/:correlationId'
114
+ router.get(path, checkAuth(opts?.endpoint), async (request: GetAuthorizationRequestStatus, response: Response) => {
115
+ try {
116
+ console.log('Received auth-status request...')
117
+ const correlationId: string = request.params.correlationId
118
+
119
+ const requestState = await context.agent.siopGetAuthRequestState({
120
+ correlationId,
121
+ errorOnNotFound: false
122
+ })
123
+
124
+ if (!requestState) {
125
+ console.log(`No authorization request could be found for the given correlationId. correlationId: ${correlationId}`)
126
+ return sendErrorResponse(response, 404, { status: 404, message: 'No authorization request could be found' })
127
+ }
128
+
129
+ let responseState
130
+ if (requestState.status === 'authorization_request_created') {
131
+ responseState = (await context.agent.siopGetAuthResponseState({ correlationId, errorOnNotFound: false }))
132
+ }
133
+ const overallState = responseState ?? requestState
134
+
135
+ const statusBody = {
136
+ status: overallState.status,
137
+ correlation_id: overallState.correlationId,
138
+ query_id: overallState.queryId,
139
+ last_updated: overallState.lastUpdated,
140
+ ...((responseState?.status === AuthorizationResponseStateStatus.VERIFIED && responseState.verifiedData !== undefined) && { verified_data: responseState.verifiedData }),
141
+ ...(overallState.error && { message: overallState.error.message })
142
+ } satisfies GetAuthStatusResponse
143
+ console.debug(`Will send auth status: ${JSON.stringify(statusBody)}`)
144
+
145
+ if (overallState.status === 'error') {
146
+ return response.status(500).json(statusBody)
147
+ }
148
+ return response.status(200).json(statusBody)
149
+ } catch (error) {
150
+ return sendErrorResponse(response, 500, { status: 500, message: error.message }, error)
151
+ }
152
+ })
153
+ }
154
+
155
+ export function getDefinitionsEndpoint(router: Router, context: IRequiredContext, opts?: ISingleEndpointOpts) {
156
+ if (opts?.enabled === false) {
157
+ console.log(`getDefinitions universal OID4VP endpoint is disabled`)
158
+ return
159
+ }
160
+
161
+ const path = opts?.path ?? '/backend/definitions'
162
+ router.get(path, checkAuth(opts?.endpoint), async (request: Request, response: Response) => {
163
+ try {
164
+ const definitions = await context.agent.pdmGetDefinitions()
165
+ response.statusCode = 200
166
+ return response.json(definitions)
167
+ } catch (error) {
168
+ return sendErrorResponse(response, 500, { status: 500, message: error.message }, error)
169
+ }
170
+ })
171
+ }
@@ -1,183 +0,0 @@
1
- import { AuthorizationRequestState, AuthorizationResponseStateStatus } from '@sphereon/did-auth-siop'
2
- import { checkAuth, ISingleEndpointOpts, sendErrorResponse } from '@sphereon/ssi-express-support'
3
- import { AuthStatusResponse, GenerateAuthRequestURIResponse, uriWithBase } from '@sphereon/ssi-sdk.siopv2-oid4vp-common'
4
- import { AuthorizationResponseStateWithVerifiedData, VerifiedDataMode } from '@sphereon/ssi-sdk.siopv2-oid4vp-rp-auth'
5
- import { Request, Response, Router } from 'express'
6
- import uuid from 'short-uuid'
7
- import { ICreateAuthRequestWebappEndpointOpts, IRequiredContext } from './types'
8
- import { shaHasher as defaultHasher } from '@sphereon/ssi-sdk.core'
9
-
10
- export function createAuthRequestWebappEndpoint(router: Router, context: IRequiredContext, opts?: ICreateAuthRequestWebappEndpointOpts) {
11
- if (opts?.enabled === false) {
12
- console.log(`createAuthRequest Webapp endpoint is disabled`)
13
- return
14
- }
15
- const path = opts?.path ?? '/webapp/definitions/:definitionId/auth-requests'
16
- router.post(path, checkAuth(opts?.endpoint), async (request: Request, response: Response) => {
17
- try {
18
- // if (!request.agent) throw Error('No agent configured')
19
- const definitionId = request.params.definitionId
20
- if (!definitionId) {
21
- return sendErrorResponse(response, 400, 'No definitionId query parameter provided')
22
- }
23
- const state: string = request.body.state ?? uuid.uuid()
24
- const correlationId = request.body.correlationId ?? state
25
- const qrCodeOpts = request.body.qrCodeOpts ?? opts?.qrCodeOpts
26
-
27
- const requestByReferenceURI = uriWithBase(`/siop/definitions/${definitionId}/auth-requests/${state}`, {
28
- baseURI: opts?.siopBaseURI,
29
- })
30
- const responseURI = uriWithBase(`/siop/definitions/${definitionId}/auth-responses/${state}`, { baseURI: opts?.siopBaseURI })
31
- // first version is for backwards compat
32
- const responseRedirectURI =
33
- ('response_redirect_uri' in request.body && (request.body.response_redirect_uri as string | undefined)) ??
34
- ('responseRedirectURI' in request.body && (request.body.responseRedirectURI as string | undefined))
35
-
36
- const authRequestURI = await context.agent.siopCreateAuthRequestURI({
37
- definitionId,
38
- correlationId,
39
- state,
40
- nonce: uuid.uuid(),
41
- requestByReferenceURI,
42
- responseURIType: 'response_uri',
43
- responseURI,
44
- ...(responseRedirectURI && { responseRedirectURI }),
45
- })
46
-
47
- let qrCodeDataUri: string | undefined
48
- if (qrCodeOpts) {
49
- const { AwesomeQR } = await import('awesome-qr')
50
- const qrCode = new AwesomeQR({ ...qrCodeOpts, text: authRequestURI })
51
- qrCodeDataUri = `data:image/png;base64,${(await qrCode.draw())!.toString('base64')}`
52
- }
53
- const authRequestBody: GenerateAuthRequestURIResponse = {
54
- correlationId,
55
- state,
56
- definitionId,
57
- authRequestURI,
58
- authStatusURI: `${uriWithBase(opts?.webappAuthStatusPath ?? '/webapp/auth-status', { baseURI: opts?.webappBaseURI })}`,
59
- ...(qrCodeDataUri && { qrCodeDataUri }),
60
- }
61
- console.log(`Auth Request URI data to send back: ${JSON.stringify(authRequestBody)}`)
62
- return response.json(authRequestBody)
63
- } catch (error) {
64
- return sendErrorResponse(response, 500, 'Could not create an authorization request URI', error)
65
- }
66
- })
67
- }
68
-
69
- export function authStatusWebappEndpoint(router: Router, context: IRequiredContext, opts?: ISingleEndpointOpts) {
70
- if (opts?.enabled === false) {
71
- console.log(`authStatus Webapp endpoint is disabled`)
72
- return
73
- }
74
- const path = opts?.path ?? '/webapp/auth-status'
75
- router.post(path, checkAuth(opts?.endpoint), async (request: Request, response: Response) => {
76
- try {
77
- console.log('Received auth-status request...')
78
- const correlationId: string = request.body.correlationId as string
79
- const definitionId: string = request.body.definitionId as string
80
-
81
- const requestState =
82
- correlationId && definitionId
83
- ? await context.agent.siopGetAuthRequestState({
84
- correlationId,
85
- definitionId,
86
- errorOnNotFound: false,
87
- })
88
- : undefined
89
- if (!requestState || !definitionId || !correlationId) {
90
- console.log(
91
- `No authentication request mapping could be found for the given URL. correlation: ${correlationId}, definitionId: ${definitionId}`,
92
- )
93
- response.statusCode = 404
94
- const statusBody: AuthStatusResponse = {
95
- status: requestState ? requestState.status : 'error',
96
- error: 'No authentication request mapping could be found for the given URL.',
97
- correlationId,
98
- definitionId,
99
- lastUpdated: requestState ? requestState.lastUpdated : Date.now(),
100
- }
101
- return response.json(statusBody)
102
- }
103
-
104
- let includeVerifiedData: VerifiedDataMode = VerifiedDataMode.NONE
105
- if ('includeVerifiedData' in request.body) {
106
- includeVerifiedData = request.body.includeVerifiedData as VerifiedDataMode
107
- }
108
-
109
- let responseState
110
- if (requestState.status === 'sent') {
111
- responseState = (await context.agent.siopGetAuthResponseState({
112
- correlationId,
113
- definitionId,
114
- includeVerifiedData: includeVerifiedData,
115
- errorOnNotFound: false,
116
- })) as AuthorizationResponseStateWithVerifiedData
117
- }
118
- const overallState: AuthorizationRequestState | AuthorizationResponseStateWithVerifiedData = responseState ?? requestState
119
-
120
- const statusBody: AuthStatusResponse = {
121
- status: overallState.status,
122
- ...(overallState.error ? { error: overallState.error?.message } : {}),
123
- correlationId,
124
- definitionId,
125
- lastUpdated: overallState.lastUpdated,
126
- ...(responseState && responseState.status === AuthorizationResponseStateStatus.VERIFIED
127
- ? {
128
- payload: await responseState.response.mergedPayloads({ hasher: defaultHasher }),
129
- verifiedData: responseState.verifiedData,
130
- }
131
- : {}),
132
- }
133
- console.debug(`Will send auth status: ${JSON.stringify(statusBody)}`)
134
- if (overallState.status === 'error') {
135
- response.statusCode = 500
136
- return response.json(statusBody)
137
- }
138
- response.statusCode = 200
139
- return response.json(statusBody)
140
- } catch (error) {
141
- return sendErrorResponse(response, 500, error.message, error)
142
- }
143
- })
144
- }
145
-
146
- export function removeAuthRequestStateWebappEndpoint(router: Router, context: IRequiredContext, opts?: ISingleEndpointOpts) {
147
- if (opts?.enabled === false) {
148
- console.log(`removeAuthStatus Webapp endpoint is disabled`)
149
- return
150
- }
151
- const path = opts?.path ?? '/webapp/definitions/:definitionId/auth-requests/:correlationId'
152
- router.delete(path, checkAuth(opts?.endpoint), async (request: Request, response: Response) => {
153
- try {
154
- const correlationId: string = request.params.correlationId
155
- const definitionId: string = request.params.definitionId
156
- if (!correlationId || !definitionId) {
157
- console.log(`No authorization request could be found for the given url. correlationId: ${correlationId}, definitionId: ${definitionId}`)
158
- return sendErrorResponse(response, 404, 'No authorization request could be found')
159
- }
160
- response.statusCode = 200
161
- return response.json(await context.agent.siopDeleteAuthState({ definitionId, correlationId }))
162
- } catch (error) {
163
- return sendErrorResponse(response, 500, error.message, error)
164
- }
165
- })
166
- }
167
-
168
- export function getDefinitionsEndpoint(router: Router, context: IRequiredContext, opts?: ISingleEndpointOpts) {
169
- if (opts?.enabled === false) {
170
- console.log(`getDefinitions Webapp endpoint is disabled`)
171
- return
172
- }
173
- const path = opts?.path ?? '/webapp/definitions'
174
- router.get(path, checkAuth(opts?.endpoint), async (request: Request, response: Response) => {
175
- try {
176
- const definitions = await context.agent.pdmGetDefinitions()
177
- response.statusCode = 200
178
- return response.json(definitions)
179
- } catch (error) {
180
- return sendErrorResponse(response, 500, error.message, error)
181
- }
182
- })
183
- }