@learncard/openid4vc-plugin 0.0.1
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/LICENSE +21 -0
- package/README.md +592 -0
- package/dist/dcql/adapt.d.ts +80 -0
- package/dist/dcql/adapt.d.ts.map +1 -0
- package/dist/dcql/build.d.ts +122 -0
- package/dist/dcql/build.d.ts.map +1 -0
- package/dist/dcql/compose.d.ts +78 -0
- package/dist/dcql/compose.d.ts.map +1 -0
- package/dist/dcql/index.d.ts +18 -0
- package/dist/dcql/index.d.ts.map +1 -0
- package/dist/dcql/parse.d.ts +16 -0
- package/dist/dcql/parse.d.ts.map +1 -0
- package/dist/dcql/respond.d.ts +115 -0
- package/dist/dcql/respond.d.ts.map +1 -0
- package/dist/dcql/select.d.ts +63 -0
- package/dist/dcql/select.d.ts.map +1 -0
- package/dist/dcql/types.d.ts +93 -0
- package/dist/dcql/types.d.ts.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/offer/index.d.ts +4 -0
- package/dist/offer/index.d.ts.map +1 -0
- package/dist/offer/normalize.d.ts +15 -0
- package/dist/offer/normalize.d.ts.map +1 -0
- package/dist/offer/parse.d.ts +24 -0
- package/dist/offer/parse.d.ts.map +1 -0
- package/dist/offer/types.d.ts +92 -0
- package/dist/offer/types.d.ts.map +1 -0
- package/dist/openid4vc-plugin.cjs.development.js +27402 -0
- package/dist/openid4vc-plugin.cjs.development.js.map +7 -0
- package/dist/openid4vc-plugin.cjs.production.min.js +146 -0
- package/dist/openid4vc-plugin.cjs.production.min.js.map +7 -0
- package/dist/openid4vc-plugin.esm.js +27396 -0
- package/dist/openid4vc-plugin.esm.js.map +7 -0
- package/dist/plugin.d.ts +12 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/siop/index.d.ts +11 -0
- package/dist/siop/index.d.ts.map +1 -0
- package/dist/siop/sign.d.ts +92 -0
- package/dist/siop/sign.d.ts.map +1 -0
- package/dist/types.d.ts +359 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/vci/accept.d.ts +24 -0
- package/dist/vci/accept.d.ts.map +1 -0
- package/dist/vci/auth-code.d.ts +148 -0
- package/dist/vci/auth-code.d.ts.map +1 -0
- package/dist/vci/decode.d.ts +65 -0
- package/dist/vci/decode.d.ts.map +1 -0
- package/dist/vci/errors.d.ts +22 -0
- package/dist/vci/errors.d.ts.map +1 -0
- package/dist/vci/index.d.ts +12 -0
- package/dist/vci/index.d.ts.map +1 -0
- package/dist/vci/metadata.d.ts +25 -0
- package/dist/vci/metadata.d.ts.map +1 -0
- package/dist/vci/pkce.d.ts +85 -0
- package/dist/vci/pkce.d.ts.map +1 -0
- package/dist/vci/proof.d.ts +43 -0
- package/dist/vci/proof.d.ts.map +1 -0
- package/dist/vci/request.d.ts +48 -0
- package/dist/vci/request.d.ts.map +1 -0
- package/dist/vci/store.d.ts +89 -0
- package/dist/vci/store.d.ts.map +1 -0
- package/dist/vci/token.d.ts +16 -0
- package/dist/vci/token.d.ts.map +1 -0
- package/dist/vci/types.d.ts +156 -0
- package/dist/vci/types.d.ts.map +1 -0
- package/dist/vp/client-id-prefix.d.ts +115 -0
- package/dist/vp/client-id-prefix.d.ts.map +1 -0
- package/dist/vp/encrypt.d.ts +221 -0
- package/dist/vp/encrypt.d.ts.map +1 -0
- package/dist/vp/index.d.ts +27 -0
- package/dist/vp/index.d.ts.map +1 -0
- package/dist/vp/parse.d.ts +60 -0
- package/dist/vp/parse.d.ts.map +1 -0
- package/dist/vp/pex.d.ts +83 -0
- package/dist/vp/pex.d.ts.map +1 -0
- package/dist/vp/present.d.ts +126 -0
- package/dist/vp/present.d.ts.map +1 -0
- package/dist/vp/request-object.d.ts +99 -0
- package/dist/vp/request-object.d.ts.map +1 -0
- package/dist/vp/select.d.ts +137 -0
- package/dist/vp/select.d.ts.map +1 -0
- package/dist/vp/sign.d.ts +125 -0
- package/dist/vp/sign.d.ts.map +1 -0
- package/dist/vp/submit.d.ts +175 -0
- package/dist/vp/submit.d.ts.map +1 -0
- package/dist/vp/types.d.ts +255 -0
- package/dist/vp/types.d.ts.map +1 -0
- package/package.json +52 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { PresentationSubmission } from './select';
|
|
2
|
+
import { VpToken } from './sign';
|
|
3
|
+
import { type JarmClientMetadata } from './encrypt';
|
|
4
|
+
import type { ProofJwtSigner } from '../vci/types';
|
|
5
|
+
/**
|
|
6
|
+
* Slice 7c / 7d — **direct_post + direct_post.jwt transport**.
|
|
7
|
+
*
|
|
8
|
+
* POST a signed `vp_token` (and, for PEX, a `presentation_submission`)
|
|
9
|
+
* to the verifier's `response_uri` per OID4VP §8. Pure transport —
|
|
10
|
+
* no signing, no PEX/DCQL evaluation, no request-object parsing.
|
|
11
|
+
*
|
|
12
|
+
* Two response modes are supported:
|
|
13
|
+
*
|
|
14
|
+
* - **`direct_post`** (§8.2) — form fields go on the wire as
|
|
15
|
+
* cleartext (`vp_token`, `presentation_submission`, `state`,
|
|
16
|
+
* `id_token` directly URL-encoded). What every walt.id-class
|
|
17
|
+
* verifier accepts today.
|
|
18
|
+
*
|
|
19
|
+
* - **`direct_post.jwt`** (§8.3) — the same fields are packed into
|
|
20
|
+
* a JSON payload, optionally signed by the wallet, then encrypted
|
|
21
|
+
* to the verifier's published encryption key. The single resulting
|
|
22
|
+
* compact JOSE string goes on the wire as one form field named
|
|
23
|
+
* `response`. What EUDI / EU pilot deployments require for
|
|
24
|
+
* production. Encryption is delegated to `./encrypt.ts`; this
|
|
25
|
+
* module just dispatches.
|
|
26
|
+
*
|
|
27
|
+
* ## PEX vs DCQL submissions
|
|
28
|
+
*
|
|
29
|
+
* OID4VP defines two distinct response shapes:
|
|
30
|
+
*
|
|
31
|
+
* - **PEX** (Draft 22 and earlier, still used by every walt.id-class
|
|
32
|
+
* verifier in the wild) → fields `vp_token` + `presentation_submission`.
|
|
33
|
+
* `vp_token` is a single signed VP; `presentation_submission`
|
|
34
|
+
* carries the descriptor_map that routes inner credentials.
|
|
35
|
+
*
|
|
36
|
+
* - **DCQL** (OID4VP 1.0 §6.4) → field `vp_token` only, valued
|
|
37
|
+
* as a JSON-encoded object whose keys are `credential_query_id`
|
|
38
|
+
* strings and whose values are signed presentations. NO
|
|
39
|
+
* `presentation_submission` field — the keying carries the routing
|
|
40
|
+
* implicitly. Callers using the DCQL pipeline (`dcql/respond.ts`)
|
|
41
|
+
* pass `submission: undefined` (or omit it) so this transport
|
|
42
|
+
* leaves the field off the response body.
|
|
43
|
+
*
|
|
44
|
+
* Both query-language splits work in either response mode. JARM
|
|
45
|
+
* just wraps the same payload in a JOSE blob.
|
|
46
|
+
*
|
|
47
|
+
* ## Encoding (cleartext mode)
|
|
48
|
+
*
|
|
49
|
+
* OID4VP requires `application/x-www-form-urlencoded`, even though
|
|
50
|
+
* `vp_token` and `presentation_submission` are structured values.
|
|
51
|
+
* Stringification rules:
|
|
52
|
+
*
|
|
53
|
+
* - `vp_token` as a `string` (jwt_vp_json compact JWS) → used verbatim.
|
|
54
|
+
* - `vp_token` as an object (ldp_vp signed VP, OR a DCQL vp_token
|
|
55
|
+
* object keyed by credential_query_id) → `JSON.stringify`.
|
|
56
|
+
* - `presentation_submission` → always `JSON.stringify` when present.
|
|
57
|
+
* - `state` → echoed verbatim if present.
|
|
58
|
+
*
|
|
59
|
+
* ## Encoding (JARM mode)
|
|
60
|
+
*
|
|
61
|
+
* Single form field: `response=<JOSE blob>`. Same form-urlencoded
|
|
62
|
+
* content type so verifier servers don't need protocol-aware framing
|
|
63
|
+
* — the JOSE blob is just one parameter value.
|
|
64
|
+
*
|
|
65
|
+
* ## Response handling
|
|
66
|
+
*
|
|
67
|
+
* Spec-compliant verifiers respond 200 OK with either an empty body
|
|
68
|
+
* (success) or `{ "redirect_uri": "…" }` (wallet is asked to deep-link
|
|
69
|
+
* back). We parse both shapes and surface anything else through
|
|
70
|
+
* `SubmitResponse.body` unchanged so callers can debug vendor-specific
|
|
71
|
+
* returns (e.g. walt.id's `{ success: true }`).
|
|
72
|
+
*
|
|
73
|
+
* HTTP-level failures become typed `VpSubmitError`s so UIs can render
|
|
74
|
+
* "connection issue" vs "verifier rejected the VP" correctly.
|
|
75
|
+
*/
|
|
76
|
+
export interface SubmitPresentationOptions {
|
|
77
|
+
/**
|
|
78
|
+
* The `response_uri` from the verifier's Authorization Request. We
|
|
79
|
+
* POST here, form-encoded, per OID4VP §8.
|
|
80
|
+
*/
|
|
81
|
+
responseUri: string;
|
|
82
|
+
/**
|
|
83
|
+
* Signed VP token. Three shapes are accepted:
|
|
84
|
+
* - PEX `jwt_vp_json` → compact JWS string
|
|
85
|
+
* - PEX `ldp_vp` → signed VP JSON object
|
|
86
|
+
* - DCQL response → JSON object keyed by `credential_query_id`,
|
|
87
|
+
* values are per-query signed presentations
|
|
88
|
+
*/
|
|
89
|
+
vpToken: VpToken;
|
|
90
|
+
/**
|
|
91
|
+
* DIF PEX v2 Presentation Submission. Required for PEX flows;
|
|
92
|
+
* MUST be omitted (or `undefined`) for DCQL flows — DCQL's
|
|
93
|
+
* vp_token keying provides the routing implicitly. See the
|
|
94
|
+
* module-level docstring for the full PEX-vs-DCQL split.
|
|
95
|
+
*/
|
|
96
|
+
submission?: PresentationSubmission;
|
|
97
|
+
/**
|
|
98
|
+
* SIOPv2 ID token (Slice 8). Required when the verifier asked for
|
|
99
|
+
* `response_type=vp_token id_token` or `response_type=id_token`;
|
|
100
|
+
* must be omitted otherwise. Encoded as the `id_token` form field
|
|
101
|
+
* alongside `vp_token`.
|
|
102
|
+
*/
|
|
103
|
+
idToken?: string;
|
|
104
|
+
/**
|
|
105
|
+
* The verifier's `state` parameter (if present in the Auth
|
|
106
|
+
* Request). Echoed back so the verifier can correlate the
|
|
107
|
+
* response with the pending session. Omitted when absent.
|
|
108
|
+
*/
|
|
109
|
+
state?: string;
|
|
110
|
+
/**
|
|
111
|
+
* Verifier's `response_mode` from the Authorization Request.
|
|
112
|
+
* Defaults to `direct_post` (cleartext). Set to `direct_post.jwt`
|
|
113
|
+
* to send a JARM (encrypted, optionally signed) response. Any
|
|
114
|
+
* other value is treated as cleartext for forward-compat — the
|
|
115
|
+
* caller can detect and reject unsupported modes upstream rather
|
|
116
|
+
* than have the transport silently downgrade.
|
|
117
|
+
*/
|
|
118
|
+
responseMode?: string;
|
|
119
|
+
/**
|
|
120
|
+
* Verifier's `client_metadata` from the Authorization Request.
|
|
121
|
+
* Required when `responseMode === 'direct_post.jwt'` (carries
|
|
122
|
+
* the JWE algorithms + verifier's encryption JWKS). Ignored in
|
|
123
|
+
* cleartext mode.
|
|
124
|
+
*/
|
|
125
|
+
clientMetadata?: JarmClientMetadata;
|
|
126
|
+
/**
|
|
127
|
+
* Verifier's `nonce` from the Authorization Request. Required
|
|
128
|
+
* when `responseMode === 'direct_post.jwt'` (used as the JWE
|
|
129
|
+
* `apv` ECDH-ES KDF input per OID4VP §8.3 ¶6). Ignored in
|
|
130
|
+
* cleartext mode.
|
|
131
|
+
*/
|
|
132
|
+
nonce?: string;
|
|
133
|
+
/**
|
|
134
|
+
* Wallet signer — same shape as VCI proof-of-possession + outer
|
|
135
|
+
* VP signing. Required when JARM is in use AND the verifier
|
|
136
|
+
* declared `authorization_signed_response_alg` (the wallet must
|
|
137
|
+
* sign the response object before encrypting). Ignored otherwise.
|
|
138
|
+
*/
|
|
139
|
+
signer?: ProofJwtSigner;
|
|
140
|
+
/** Override fetch — defaults to `globalThis.fetch`. */
|
|
141
|
+
fetchImpl?: typeof fetch;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Shape of a successful `direct_post` response. `redirectUri` is
|
|
145
|
+
* populated when the verifier requested wallet redirect (OID4VP §8.2).
|
|
146
|
+
*/
|
|
147
|
+
export interface SubmitPresentationResult {
|
|
148
|
+
/** HTTP status (always 2xx for successful submissions; otherwise we throw). */
|
|
149
|
+
status: number;
|
|
150
|
+
/**
|
|
151
|
+
* Redirect URI the wallet should deep-link to. Present when the
|
|
152
|
+
* verifier wants the wallet to bounce the user back (e.g. to an
|
|
153
|
+
* in-browser "success" page).
|
|
154
|
+
*/
|
|
155
|
+
redirectUri?: string;
|
|
156
|
+
/**
|
|
157
|
+
* Raw parsed body. `object` when the verifier returned JSON,
|
|
158
|
+
* `string` for plain text, `undefined` for empty. Preserved so
|
|
159
|
+
* callers can debug vendor-specific fields.
|
|
160
|
+
*/
|
|
161
|
+
body: unknown;
|
|
162
|
+
}
|
|
163
|
+
export type VpSubmitErrorCode = 'invalid_input' | 'no_fetch' | 'network_error' | 'server_error' | 'jarm_encrypt_failed';
|
|
164
|
+
export declare class VpSubmitError extends Error {
|
|
165
|
+
readonly code: VpSubmitErrorCode;
|
|
166
|
+
readonly status?: number;
|
|
167
|
+
readonly body?: unknown;
|
|
168
|
+
constructor(code: VpSubmitErrorCode, message: string, extra?: {
|
|
169
|
+
status?: number;
|
|
170
|
+
body?: unknown;
|
|
171
|
+
cause?: unknown;
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
export declare const submitPresentation: (options: SubmitPresentationOptions) => Promise<SubmitPresentationResult>;
|
|
175
|
+
//# sourceMappingURL=submit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"submit.d.ts","sourceRoot":"","sources":["../../src/vp/submit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACjC,OAAO,EAGH,KAAK,kBAAkB,EAE1B,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsEG;AAMH,MAAM,WAAW,yBAAyB;IACtC;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;;;;;OAMG;IACH,OAAO,EAAE,OAAO,CAAC;IAEjB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,sBAAsB,CAAC;IAEpC;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,kBAAkB,CAAC;IAEpC;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;;;OAKG;IACH,MAAM,CAAC,EAAE,cAAc,CAAC;IAExB,uDAAuD;IACvD,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC5B;AAED;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACrC,+EAA+E;IAC/E,MAAM,EAAE,MAAM,CAAC;IAEf;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;;OAIG;IACH,IAAI,EAAE,OAAO,CAAC;CACjB;AAMD,MAAM,MAAM,iBAAiB,GACvB,eAAe,GACf,UAAU,GACV,eAAe,GACf,cAAc,GACd,qBAAqB,CAAC;AAE5B,qBAAa,aAAc,SAAQ,KAAK;IACpC,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;gBAGpB,IAAI,EAAE,iBAAiB,EACvB,OAAO,EAAE,MAAM,EACf,KAAK,GAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAO;CAWvE;AAMD,eAAO,MAAM,kBAAkB,YAClB,yBAAyB,KACnC,OAAO,CAAC,wBAAwB,CAwFlC,CAAC"}
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenID for Verifiable Presentations (OID4VP) Authorization Request types
|
|
3
|
+
* plus the DIF Presentation Exchange v2.0 subset the plugin consumes.
|
|
4
|
+
*
|
|
5
|
+
* Spec references:
|
|
6
|
+
* - OpenID4VP Draft 22: https://openid.net/specs/openid-4-verifiable-presentations-1_0.html
|
|
7
|
+
* - DIF PEX v2.0: https://identity.foundation/presentation-exchange/spec/v2.0.0/
|
|
8
|
+
*
|
|
9
|
+
* We target Draft 22 (`response_uri`) but tolerate legacy `redirect_uri`
|
|
10
|
+
* when the caller used an older verifier implementation.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Stable error codes surfaced to UI layers. Every parse failure maps to
|
|
14
|
+
* exactly one of these so UI can localize copy without string-matching
|
|
15
|
+
* `Error.message`.
|
|
16
|
+
*/
|
|
17
|
+
export type VpErrorCode = 'invalid_uri' | 'invalid_json' | 'missing_client_id' | 'missing_nonce' | 'missing_response_type' | 'unsupported_response_type' | 'missing_response_target' | 'missing_presentation_definition' | 'invalid_presentation_definition' | 'both_definition_and_uri' | 'request_object_not_supported' | 'presentation_definition_fetch_failed'
|
|
18
|
+
/**
|
|
19
|
+
* The Authorization Request carried a `dcql_query` that wasn't a
|
|
20
|
+
* JSON object, failed `DcqlQuery.parse` (structure), or failed
|
|
21
|
+
* `DcqlQuery.validate` (content). Distinct from
|
|
22
|
+
* `invalid_presentation_definition` so UI can localize the two
|
|
23
|
+
* separately; the underlying `dcql` library error rides along on
|
|
24
|
+
* `Error.cause` for debug.
|
|
25
|
+
*/
|
|
26
|
+
| 'invalid_dcql_query'
|
|
27
|
+
/**
|
|
28
|
+
* The Authorization Request carried BOTH `presentation_definition`
|
|
29
|
+
* (or `..._uri`) AND `dcql_query`. OID4VP 1.0 §5.3 forbids this:
|
|
30
|
+
* the verifier picks ONE query language per request. Without this
|
|
31
|
+
* guard we'd silently route on whichever one we happened to read
|
|
32
|
+
* first, which would mask verifier-side bugs.
|
|
33
|
+
*/
|
|
34
|
+
| 'both_pex_and_dcql';
|
|
35
|
+
/**
|
|
36
|
+
* Thrown by the parser/resolver and by PEX selection helpers. The `code`
|
|
37
|
+
* field is the stable contract; `message` and `cause` are diagnostic.
|
|
38
|
+
*/
|
|
39
|
+
export declare class VpError extends Error {
|
|
40
|
+
readonly code: VpErrorCode;
|
|
41
|
+
constructor(code: VpErrorCode, message: string, options?: {
|
|
42
|
+
cause?: unknown;
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Result of parsing an OID4VP Authorization Request URI.
|
|
47
|
+
*
|
|
48
|
+
* - `by_value` — every parameter was inline in the URI; the request is
|
|
49
|
+
* fully resolved and ready for PEX matching (Slice 6c+).
|
|
50
|
+
* - `by_reference_request_uri` — the verifier delegated the full request
|
|
51
|
+
* to a signed JWT fetched from `request_uri`; deferred to Slice 7.
|
|
52
|
+
* - `by_reference_request_jwt` — the request was embedded inline as a
|
|
53
|
+
* signed JWS via the `request` parameter; deferred to Slice 7.
|
|
54
|
+
*
|
|
55
|
+
* The `by_reference_*` variants intentionally don't attempt to decode
|
|
56
|
+
* the JWS — signature verification requires trust anchors (x5c chain,
|
|
57
|
+
* registered client metadata, did:web resolution) that belong in Slice 7.
|
|
58
|
+
*/
|
|
59
|
+
export type ParsedAuthorizationRequest = {
|
|
60
|
+
kind: 'by_value';
|
|
61
|
+
request: AuthorizationRequest;
|
|
62
|
+
} | {
|
|
63
|
+
kind: 'by_reference_request_uri';
|
|
64
|
+
requestUri: string;
|
|
65
|
+
rawParams: URLSearchParams;
|
|
66
|
+
} | {
|
|
67
|
+
kind: 'by_reference_request_jwt';
|
|
68
|
+
jwt: string;
|
|
69
|
+
rawParams: URLSearchParams;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Canonical Authorization Request shape the plugin operates on. Values
|
|
73
|
+
* come from either the inline URI params or the decoded signed Request
|
|
74
|
+
* Object (Slice 7). Field names match the OID4VP spec so they round-trip
|
|
75
|
+
* cleanly back into the `direct_post` response.
|
|
76
|
+
*/
|
|
77
|
+
export interface AuthorizationRequest {
|
|
78
|
+
/**
|
|
79
|
+
* Verifier identifier. Shape depends on `client_id_scheme`:
|
|
80
|
+
* - `did` → a DID URL
|
|
81
|
+
* - `x509_san_dns` / `x509_san_uri` → a hostname/URL backed by the
|
|
82
|
+
* signing cert's SAN
|
|
83
|
+
* - `redirect_uri` → the verifier's response_uri host
|
|
84
|
+
* - `pre-registered` → an opaque string registered out-of-band
|
|
85
|
+
*/
|
|
86
|
+
client_id: string;
|
|
87
|
+
client_id_scheme?: string;
|
|
88
|
+
/**
|
|
89
|
+
* Space-separated list — typically `vp_token` alone, or
|
|
90
|
+
* `vp_token id_token` for SIOPv2 + VP combined.
|
|
91
|
+
*/
|
|
92
|
+
response_type: string;
|
|
93
|
+
/**
|
|
94
|
+
* `direct_post` — POST the VP token to `response_uri` as a form body.
|
|
95
|
+
* `direct_post.jwt` — same, but the body is a JWE.
|
|
96
|
+
* `fragment` / `query` — legacy browser-redirect modes.
|
|
97
|
+
*
|
|
98
|
+
* When omitted for a `vp_token` response_type, the spec's default is
|
|
99
|
+
* `fragment`, but every real-world wallet assumes `direct_post`.
|
|
100
|
+
*/
|
|
101
|
+
response_mode?: string;
|
|
102
|
+
/**
|
|
103
|
+
* Draft 22+: destination for the VP token when `response_mode` is
|
|
104
|
+
* `direct_post*`. Mutually exclusive with legacy `redirect_uri` for
|
|
105
|
+
* direct-post flows, though older verifiers may still send
|
|
106
|
+
* `redirect_uri` here.
|
|
107
|
+
*/
|
|
108
|
+
response_uri?: string;
|
|
109
|
+
/**
|
|
110
|
+
* Legacy (Draft ≤ 17): combined redirect + response destination.
|
|
111
|
+
* Still used by some verifiers in the wild. The resolver surfaces
|
|
112
|
+
* whichever one arrived under `response_uri` for consistency.
|
|
113
|
+
*/
|
|
114
|
+
redirect_uri?: string;
|
|
115
|
+
nonce: string;
|
|
116
|
+
state?: string;
|
|
117
|
+
/**
|
|
118
|
+
* Inline DIF PEX v2 Presentation Definition. Mutually exclusive
|
|
119
|
+
* with `dcql_query` per OID4VP 1.0 §5.3 — a verifier expresses
|
|
120
|
+
* its credential ask in EITHER PEX OR DCQL, never both.
|
|
121
|
+
*
|
|
122
|
+
* Exactly one of `presentation_definition` /
|
|
123
|
+
* `presentation_definition_uri` / `dcql_query` /
|
|
124
|
+
* `scope` (with a well-known scope→PD mapping) is expected.
|
|
125
|
+
*
|
|
126
|
+
* The plugin auto-routes on whichever is present; PEX is the legacy
|
|
127
|
+
* path (every pre-1.0 verifier), DCQL is the OID4VP 1.0+ path.
|
|
128
|
+
*/
|
|
129
|
+
presentation_definition?: PresentationDefinition;
|
|
130
|
+
/**
|
|
131
|
+
* URL returning the inline `presentation_definition` JSON. Resolved
|
|
132
|
+
* by {@link resolvePresentationDefinitionByReference}.
|
|
133
|
+
*/
|
|
134
|
+
presentation_definition_uri?: string;
|
|
135
|
+
/**
|
|
136
|
+
* **OID4VP 1.0 §6** Digital Credentials Query Language query.
|
|
137
|
+
*
|
|
138
|
+
* Mutually exclusive with `presentation_definition` —
|
|
139
|
+
* verifiers using DCQL set this and omit PEX, and vice versa.
|
|
140
|
+
* Coexistence is at the plugin level (we accept either),
|
|
141
|
+
* NOT at the wire level (a single auth request never carries both).
|
|
142
|
+
*
|
|
143
|
+
* Stored as a parsed-and-validated value of the `dcql` library's
|
|
144
|
+
* `DcqlQuery` type so downstream selector code can run
|
|
145
|
+
* `DcqlQuery.query(...)` without re-parsing. The plugin's
|
|
146
|
+
* resolver (in `./parse.ts`) calls `DcqlQuery.parse(rawJson)`
|
|
147
|
+
* before populating this field — by the time it lands here, it's
|
|
148
|
+
* already been structurally + semantically validated.
|
|
149
|
+
*
|
|
150
|
+
* Unlike `presentation_definition_uri`, DCQL is **always inline**;
|
|
151
|
+
* the spec doesn't define a `dcql_query_uri` mechanism.
|
|
152
|
+
*/
|
|
153
|
+
dcql_query?: import('../dcql/types').DcqlQuery;
|
|
154
|
+
/**
|
|
155
|
+
* Verifier metadata (supported formats, response-encryption JWKS,
|
|
156
|
+
* etc.). Consumed by Slice 7 when building the direct_post.jwt
|
|
157
|
+
* response.
|
|
158
|
+
*/
|
|
159
|
+
client_metadata?: Record<string, unknown>;
|
|
160
|
+
/** URL variant of {@link client_metadata}. */
|
|
161
|
+
client_metadata_uri?: string;
|
|
162
|
+
/**
|
|
163
|
+
* Space-separated OAuth scopes. Mainly used by SIOPv2 (`openid`) and
|
|
164
|
+
* by verifiers that pre-register scope→presentation_definition
|
|
165
|
+
* mappings. Passed through verbatim for Slice 8.
|
|
166
|
+
*/
|
|
167
|
+
scope?: string;
|
|
168
|
+
/**
|
|
169
|
+
* Any additional parameters the verifier included. Kept so callers
|
|
170
|
+
* writing to the direct_post response can echo `state`, custom
|
|
171
|
+
* extensions, etc. without losing fidelity.
|
|
172
|
+
*/
|
|
173
|
+
extra?: Record<string, string>;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* DIF PEX v2 Presentation Definition. The minimum fields the plugin
|
|
177
|
+
* inspects for matching; forward-compatible extensions are preserved in
|
|
178
|
+
* `extra` so they can round-trip into the Presentation Submission.
|
|
179
|
+
*/
|
|
180
|
+
export interface PresentationDefinition {
|
|
181
|
+
id: string;
|
|
182
|
+
name?: string;
|
|
183
|
+
purpose?: string;
|
|
184
|
+
format?: Record<string, ClaimFormatDesignation>;
|
|
185
|
+
submission_requirements?: SubmissionRequirement[];
|
|
186
|
+
input_descriptors: InputDescriptor[];
|
|
187
|
+
}
|
|
188
|
+
export interface InputDescriptor {
|
|
189
|
+
id: string;
|
|
190
|
+
name?: string;
|
|
191
|
+
purpose?: string;
|
|
192
|
+
group?: string[];
|
|
193
|
+
format?: Record<string, ClaimFormatDesignation>;
|
|
194
|
+
constraints: Constraints;
|
|
195
|
+
}
|
|
196
|
+
export interface Constraints {
|
|
197
|
+
/**
|
|
198
|
+
* `required` — wallet MUST strip every field not listed in `fields[]`
|
|
199
|
+
* before presenting (selective disclosure).
|
|
200
|
+
* `preferred` — wallet SHOULD, but isn't required to.
|
|
201
|
+
*
|
|
202
|
+
* Slice 6 ignores limit_disclosure for VC 1.1 JSON-LD / JWT-VC since
|
|
203
|
+
* neither format supports field-level redaction cleanly. SD-JWT-VC
|
|
204
|
+
* support lives in a separate plugin.
|
|
205
|
+
*/
|
|
206
|
+
limit_disclosure?: 'required' | 'preferred';
|
|
207
|
+
fields?: Field[];
|
|
208
|
+
}
|
|
209
|
+
export interface Field {
|
|
210
|
+
/**
|
|
211
|
+
* JSONPath expressions evaluated (in order) against each candidate VC.
|
|
212
|
+
* The first path that yields a non-empty match wins; that match is
|
|
213
|
+
* then tested against `filter` (when present).
|
|
214
|
+
*/
|
|
215
|
+
path: string[];
|
|
216
|
+
id?: string;
|
|
217
|
+
name?: string;
|
|
218
|
+
purpose?: string;
|
|
219
|
+
/**
|
|
220
|
+
* JSON Schema (Draft 7 subset) applied to the resolved value. Slice 6
|
|
221
|
+
* supports `type`, `const`, `enum`, `pattern`, `contains`, plus the
|
|
222
|
+
* numeric/string bound keywords — which covers every filter seen in
|
|
223
|
+
* the PEX test vectors and real verifier payloads we've inspected.
|
|
224
|
+
*/
|
|
225
|
+
filter?: Record<string, unknown>;
|
|
226
|
+
/**
|
|
227
|
+
* When `true`, the field doesn't need to match for the input
|
|
228
|
+
* descriptor to be satisfied. Useful for "nice-to-have" claims.
|
|
229
|
+
*/
|
|
230
|
+
optional?: boolean;
|
|
231
|
+
/**
|
|
232
|
+
* `required` — the VC must literally contain the claim (default).
|
|
233
|
+
* `preferred` — the wallet should supply the claim if available, but
|
|
234
|
+
* may substitute a predicate proof (ZKP). We treat
|
|
235
|
+
* both as `required` until a ZKP-capable backend lands.
|
|
236
|
+
*/
|
|
237
|
+
predicate?: 'required' | 'preferred';
|
|
238
|
+
}
|
|
239
|
+
export interface SubmissionRequirement {
|
|
240
|
+
name?: string;
|
|
241
|
+
purpose?: string;
|
|
242
|
+
rule: 'all' | 'pick';
|
|
243
|
+
count?: number;
|
|
244
|
+
min?: number;
|
|
245
|
+
max?: number;
|
|
246
|
+
/** Reference to an `input_descriptor.group` value. */
|
|
247
|
+
from?: string;
|
|
248
|
+
/** Nested submission requirements for composite rules. */
|
|
249
|
+
from_nested?: SubmissionRequirement[];
|
|
250
|
+
}
|
|
251
|
+
export interface ClaimFormatDesignation {
|
|
252
|
+
alg?: string[];
|
|
253
|
+
proof_type?: string[];
|
|
254
|
+
}
|
|
255
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/vp/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@learncard/openid4vc-plugin",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "OpenID for Verifiable Credentials (OID4VCI + OID4VP + SIOPv2) holder support for LearnCard",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/openid4vc-plugin.esm.js",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"author": "Learning Economy Foundation (www.learningeconomy.io)",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"homepage": "https://github.com/learningeconomy/LearnCard/tree/main/packages/plugins/openid4vc/README.md",
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "https://github.com/learningeconomy/LearnCard"
|
|
16
|
+
},
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/learningeconomy/LearnCard/issues"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@types/jest": "^29.2.2",
|
|
22
|
+
"@types/node": "^17.0.31",
|
|
23
|
+
"aqu": "0.4.3",
|
|
24
|
+
"esbuild": "^0.27.1",
|
|
25
|
+
"esbuild-jest": "^0.5.0",
|
|
26
|
+
"esbuild-plugin-copy": "^1.3.0",
|
|
27
|
+
"jest": "^29.3.0",
|
|
28
|
+
"shx": "^0.3.4",
|
|
29
|
+
"ts-jest": "^29.0.3",
|
|
30
|
+
"tsx": "^4.20.6",
|
|
31
|
+
"@learncard/types": "5.15.0"
|
|
32
|
+
},
|
|
33
|
+
"types": "./dist/index.d.ts",
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@peculiar/x509": "^1.12.0",
|
|
36
|
+
"dcql": "^3.0.0",
|
|
37
|
+
"jose": "^5.9.6",
|
|
38
|
+
"safe-regex": "^2.1.1",
|
|
39
|
+
"@learncard/core": "9.4.18",
|
|
40
|
+
"@learncard/didkit-plugin": "^1.8.9",
|
|
41
|
+
"@learncard/vc-plugin": "^1.4.14"
|
|
42
|
+
},
|
|
43
|
+
"sideEffects": false,
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "node ./scripts/build.mjs && shx cp ./scripts/mixedEntypoint.js ./dist/index.js && tsc --p tsconfig.json",
|
|
46
|
+
"test": "jest --passWithNoTests",
|
|
47
|
+
"test:watch": "jest --watch",
|
|
48
|
+
"test:coverage": "jest --silent --ci --coverage --coverageReporters=\"text\" --coverageReporters=\"text-summary\"",
|
|
49
|
+
"try-offer": "tsx ./scripts/try-offer.ts",
|
|
50
|
+
"try-verify": "tsx ./scripts/try-verify.ts"
|
|
51
|
+
}
|
|
52
|
+
}
|