Skip to content

Commit 66678f5

Browse files
authored
docs(sdk): document Yivi attribute disjunctions (#113)
* docs(sdk): document attribute disjunctions for Yivi sign step * fix(docs): address dobby style and consistency comments
1 parent b6a6ea4 commit 66678f5

1 file changed

Lines changed: 85 additions & 1 deletion

File tree

docs/sdk/js-auth-methods.md

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,93 @@ When `includeSender` is `true`, the sender's identity is added to the encryption
7575
|-----------|------|----------|-------------|
7676
| `element` | `string` | Yes | CSS selector for the QR code container |
7777
| `senderEmail` | `string` | No | The sender's email address to prove |
78-
| `attributes` | `Array<{ t, v?, optional? }>` | No | Extra attributes to request (e.g. name, phone). Email is always included automatically. |
78+
| `attributes` | `AttrConItem[]` | No | Extra attributes to request. Each entry is either a single attribute (`AttrReq`) or a disjunction (`AttrDiscon`). Email is always included automatically. |
7979
| `includeSender` | `boolean` | No | Also encrypt for the sender so they can decrypt their own message (default: `false`) |
8080

81+
### Attribute disjunctions
82+
83+
By default each entry in `attributes` is a single attribute object (`AttrReq`). When you need to accept the same piece of information from multiple credential types (for example, a name that can come from a municipality credential, a passport, an ID card, or a driving licence), you can pass an `AttrDiscon` instead: a nested array where each inner array is one acceptable conjunction of attributes (an AND), and the outer array is the list of alternatives (an OR).
84+
85+
```ts
86+
type AttrReq = { t: string; v?: string; optional?: boolean }
87+
type AttrDiscon = AttrReq[][] // OR of ANDs
88+
type AttrConItem = AttrReq | AttrDiscon
89+
```
90+
91+
Narrow the union at runtime with `Array.isArray(item)`: `true``AttrDiscon`, `false``AttrReq`.
92+
93+
#### Optional disjunctions
94+
95+
To make a disjunction optional, add an empty array `[]` as the first alternative. Yivi treats an empty conjunction as always-satisfiable, making the whole discon skippable.
96+
97+
#### Example: optional name from any government ID
98+
99+
This requests the sender's name, but accepts any of four credential types and makes the whole group optional. If the sender does not have any of the listed credentials loaded in Yivi, they can skip the disclosure entirely.
100+
101+
```ts
102+
const sign = pg.sign.yivi({
103+
element: '#crypt-irma-qr',
104+
attributes: [
105+
// Optional name — sender can satisfy with any one of the four alternatives,
106+
// or skip entirely (the empty [] alternative is always satisfiable).
107+
[
108+
[], // skip (optional)
109+
[{ t: 'pbdf.gemeente.personalData.fullname' }], // OR: municipality full name
110+
[{ t: 'pbdf.pbdf.passport.firstName' },
111+
{ t: 'pbdf.pbdf.passport.lastName' }], // OR: passport first + last
112+
[{ t: 'pbdf.pbdf.idcard.firstName' },
113+
{ t: 'pbdf.pbdf.idcard.lastName' }], // OR: ID card first + last
114+
[{ t: 'pbdf.pbdf.drivinglicence.firstName' },
115+
{ t: 'pbdf.pbdf.drivinglicence.lastName' }], // OR: driving licence first + last
116+
],
117+
// Other optional attributes can still be flat AttrReq entries.
118+
{ t: 'pbdf.sidn-pbdf.mobilenumber.mobilenumber', optional: true },
119+
{ t: 'pbdf.gemeente.personalData.dateofbirth', optional: true },
120+
],
121+
includeSender: true,
122+
});
123+
```
124+
125+
The Yivi app presents the name group as a single step. The user picks whichever credential they have loaded; if they have none, they skip. The remainder of the `attributes` array (phone, date of birth) is presented as separate optional steps.
126+
127+
#### Mandatory disjunction
128+
129+
Remove the empty `[]` alternative to make the disclosure required. The Yivi session will not complete until the sender proves their name from one of the listed credentials:
130+
131+
```ts
132+
[
133+
[{ t: 'pbdf.gemeente.personalData.fullname' }],
134+
[{ t: 'pbdf.pbdf.passport.firstName' }, { t: 'pbdf.pbdf.passport.lastName' }],
135+
[{ t: 'pbdf.pbdf.idcard.firstName' }, { t: 'pbdf.pbdf.idcard.lastName' }],
136+
[{ t: 'pbdf.pbdf.drivinglicence.firstName' }, { t: 'pbdf.pbdf.drivinglicence.lastName' }],
137+
]
138+
```
139+
140+
::: info PKG requirement
141+
Attribute disjunctions require `@e4a/pg-js` ≥ 1.11.0 and a PKG running `postguard` with condiscon support. Earlier PKG versions only accept a flat `con` array.
142+
:::
143+
144+
#### How it maps to the PKG wire format
145+
146+
The `attributes` array is forwarded verbatim as the `con` field in the `POST /v2/request/start` body. Single `AttrReq` objects serialise as `{"t":"..."}` objects; `AttrDiscon` entries serialise as nested arrays, exactly the shape the PKG's `ConItem` untagged enum expects:
147+
148+
```json
149+
{
150+
"con": [
151+
{ "t": "pbdf.sidn-pbdf.email.email" },
152+
[
153+
[],
154+
[{ "t": "pbdf.gemeente.personalData.fullname" }],
155+
[{ "t": "pbdf.pbdf.passport.firstName" }, { "t": "pbdf.pbdf.passport.lastName" }],
156+
[{ "t": "pbdf.pbdf.idcard.firstName" }, { "t": "pbdf.pbdf.idcard.lastName" }],
157+
[{ "t": "pbdf.pbdf.drivinglicence.firstName" }, { "t": "pbdf.pbdf.drivinglicence.lastName" }]
158+
],
159+
{ "t": "pbdf.sidn-pbdf.mobilenumber.mobilenumber", "optional": true },
160+
{ "t": "pbdf.gemeente.personalData.dateofbirth", "optional": true }
161+
]
162+
}
163+
```
164+
81165
## Session Callback
82166

83167
The most flexible method. You provide a callback function that receives a session request and must return a JWT string. This lets you handle the Yivi session yourself: in a popup window, a separate process, or any custom flow.

0 commit comments

Comments
 (0)