Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 85 additions & 1 deletion docs/sdk/js-auth-methods.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,93 @@ When `includeSender` is `true`, the sender's identity is added to the encryption
|-----------|------|----------|-------------|
| `element` | `string` | Yes | CSS selector for the QR code container |
| `senderEmail` | `string` | No | The sender's email address to prove |
| `attributes` | `Array<{ t, v?, optional? }>` | No | Extra attributes to request (e.g. name, phone). Email is always included automatically. |
| `attributes` | `AttrConItem[]` | No | Extra attributes to request. Each entry is either a single attribute (`AttrReq`) or a disjunction (`AttrDiscon`). Email is always included automatically. |
| `includeSender` | `boolean` | No | Also encrypt for the sender so they can decrypt their own message (default: `false`) |

### Attribute disjunctions

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).

```ts
type AttrReq = { t: string; v?: string; optional?: boolean }
type AttrDiscon = AttrReq[][] // OR of ANDs
type AttrConItem = AttrReq | AttrDiscon
```

Narrow the union at runtime with `Array.isArray(item)`: `true` → `AttrDiscon`, `false` → `AttrReq`.

#### Optional disjunctions

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.

#### Example: optional name from any government ID
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Rule: postguard-docs writing-rules] Heading contains a colon; PostGuard style guide says to avoid colons in titles. Consider #### Optional name from any government ID (the surrounding text already establishes this is an example). Non-blocking.


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.

```ts
const sign = pg.sign.yivi({
element: '#crypt-irma-qr',
attributes: [
// Optional name — sender can satisfy with any one of the four alternatives,
// or skip entirely (the empty [] alternative is always satisfiable).
[
[], // skip (optional)
[{ t: 'pbdf.gemeente.personalData.fullname' }], // OR: municipality full name
[{ t: 'pbdf.pbdf.passport.firstName' },
{ t: 'pbdf.pbdf.passport.lastName' }], // OR: passport first + last
[{ t: 'pbdf.pbdf.idcard.firstName' },
{ t: 'pbdf.pbdf.idcard.lastName' }], // OR: ID card first + last
[{ t: 'pbdf.pbdf.drivinglicence.firstName' },
{ t: 'pbdf.pbdf.drivinglicence.lastName' }], // OR: driving licence first + last
],
// Other optional attributes can still be flat AttrReq entries.
{ t: 'pbdf.sidn-pbdf.mobilenumber.mobilenumber', optional: true },
{ t: 'pbdf.gemeente.personalData.dateofbirth', optional: true },
],
includeSender: true,
});
```

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.

#### Mandatory disjunction

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:

```ts
[
[{ t: 'pbdf.gemeente.personalData.fullname' }],
[{ t: 'pbdf.pbdf.passport.firstName' }, { t: 'pbdf.pbdf.passport.lastName' }],
[{ t: 'pbdf.pbdf.idcard.firstName' }, { t: 'pbdf.pbdf.idcard.lastName' }],
[{ t: 'pbdf.pbdf.drivinglicence.firstName' }, { t: 'pbdf.pbdf.drivinglicence.lastName' }],
]
```

::: info PKG requirement
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.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Code review] The companion PKG change encryption4all/postguard#198 is still open, so today no deployed PKG accepts the nested con shape. Consider holding this docs merge (or noting in-flight status) until the PKG side lands so users following the example don't hit serde errors.

:::

#### How it maps to the PKG wire format

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:

```json
{
"con": [
{ "t": "pbdf.sidn-pbdf.email.email" },
[
[],
[{ "t": "pbdf.gemeente.personalData.fullname" }],
[{ "t": "pbdf.pbdf.passport.firstName" }, { "t": "pbdf.pbdf.passport.lastName" }],
[{ "t": "pbdf.pbdf.idcard.firstName" }, { "t": "pbdf.pbdf.idcard.lastName" }],
[{ "t": "pbdf.pbdf.drivinglicence.firstName" }, { "t": "pbdf.pbdf.drivinglicence.lastName" }]
],
{ "t": "pbdf.sidn-pbdf.mobilenumber.mobilenumber", "optional": true },
{ "t": "pbdf.gemeente.personalData.dateofbirth", "optional": true }
]
}
```

## Session Callback

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.
Expand Down
Loading