From 7ba831b2c964071023955cac2669ed22c58c4692 Mon Sep 17 00:00:00 2001 From: Philippe Gaultier Date: Thu, 21 May 2026 15:44:01 +0200 Subject: [PATCH 1/4] add deviceauthn sequence diagrams --- docs/kratos/passwordless/08_deviceauthn.mdx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/kratos/passwordless/08_deviceauthn.mdx b/docs/kratos/passwordless/08_deviceauthn.mdx index 3bc7b403c..a3ec17ce2 100644 --- a/docs/kratos/passwordless/08_deviceauthn.mdx +++ b/docs/kratos/passwordless/08_deviceauthn.mdx @@ -797,6 +797,8 @@ And the Flutter code gets this result back: `iOS 26.2.1` (for example). At this point the key is enrolled for the identity. +[![DeviceAuthn enrollment sequence](https://mermaid.ink/img/eyJjb2RlIjogInNlcXVlbmNlRGlhZ3JhbVxuICAgIHBhcnRpY2lwYW50IEMgYXMgQ2xpZW50IChtb2JpbGUgYXBwKVxuICAgIHBhcnRpY2lwYW50IEggYXMgRGV2aWNlIGhhcmR3YXJlIChURUUvVFBNKVxuICAgIHBhcnRpY2lwYW50IFMgYXMgS3JhdG9zIHNlcnZlclxuICAgIEMtPj5TOiBQT1NUIC9zZWxmLXNlcnZpY2Uvc2V0dGluZ3MvYXBpICh4U2Vzc2lvblRva2VuKVxuICAgIFMtLT4+QzogMjAwIHNldHRpbmdzIGZsb3cge25vbmNlLCBleGlzdGluZ19rZXlzfVxuICAgIEMtPj5IOiBnZW5lcmF0ZUtleShub25jZSlcbiAgICBILS0+PkM6IHtjbGllbnRfa2V5X2lkLCBjZXJ0X2NoYWlufVxuICAgIEMtPj5TOiBQVVQgL3NlbGYtc2VydmljZS9zZXR0aW5ncz9mbG93PS4uLiB7bWV0aG9kOiBkZXZpY2VhdXRobiwgYWRkOiB7ZGV2aWNlX25hbWUsIGNsaWVudF9rZXlfaWQsIGNlcnRfY2hhaW4gb3IgYXR0ZXN0YXRpb25faW9zfX1cbiAgICBOb3RlIG92ZXIgUzogVmVyaWZ5IGNlcnQgY2hhaW4gdnMgQXBwbGUvR29vZ2xlIHJvb3QgQ0FzPGJyLz5DaGVjayBDUkxzPGJyLz5NYXRjaCBjaGFsbGVuZ2UgdG8gc3RvcmVkIG5vbmNlPGJyLz5SZWplY3Qgc29mdHdhcmUvZW11bGF0ZWQga2V5czxici8+U3RvcmUgcHVia2V5LCBlcmFzZSBjaGFsbGVuZ2VcbiAgICBTLS0+PkM6IDIwMCB1cGRhdGVkIHNldHRpbmdzIGZsb3ciLCAibWVybWFpZCI6IHsidGhlbWUiOiAiZGVmYXVsdCJ9fQ==)](https://mermaid.live/edit#eyJjb2RlIjogInNlcXVlbmNlRGlhZ3JhbVxuICAgIHBhcnRpY2lwYW50IEMgYXMgQ2xpZW50IChtb2JpbGUgYXBwKVxuICAgIHBhcnRpY2lwYW50IEggYXMgRGV2aWNlIGhhcmR3YXJlIChURUUvVFBNKVxuICAgIHBhcnRpY2lwYW50IFMgYXMgS3JhdG9zIHNlcnZlclxuICAgIEMtPj5TOiBQT1NUIC9zZWxmLXNlcnZpY2Uvc2V0dGluZ3MvYXBpICh4U2Vzc2lvblRva2VuKVxuICAgIFMtLT4+QzogMjAwIHNldHRpbmdzIGZsb3cge25vbmNlLCBleGlzdGluZ19rZXlzfVxuICAgIEMtPj5IOiBnZW5lcmF0ZUtleShub25jZSlcbiAgICBILS0+PkM6IHtjbGllbnRfa2V5X2lkLCBjZXJ0X2NoYWlufVxuICAgIEMtPj5TOiBQVVQgL3NlbGYtc2VydmljZS9zZXR0aW5ncz9mbG93PS4uLiB7bWV0aG9kOiBkZXZpY2VhdXRobiwgYWRkOiB7ZGV2aWNlX25hbWUsIGNsaWVudF9rZXlfaWQsIGNlcnRfY2hhaW4gb3IgYXR0ZXN0YXRpb25faW9zfX1cbiAgICBOb3RlIG92ZXIgUzogVmVyaWZ5IGNlcnQgY2hhaW4gdnMgQXBwbGUvR29vZ2xlIHJvb3QgQ0FzPGJyLz5DaGVjayBDUkxzPGJyLz5NYXRjaCBjaGFsbGVuZ2UgdG8gc3RvcmVkIG5vbmNlPGJyLz5SZWplY3Qgc29mdHdhcmUvZW11bGF0ZWQga2V5czxici8+U3RvcmUgcHVia2V5LCBlcmFzZSBjaGFsbGVuZ2VcbiAgICBTLS0+PkM6IDIwMCB1cGRhdGVkIHNldHRpbmdzIGZsb3ciLCAibWVybWFpZCI6IHsidGhlbWUiOiAiZGVmYXVsdCJ9fQ==) + ### Proof of device enrollment 1. When the user creates the login flow with the DeviceAuthn strategy, the client receives a server challenge. @@ -809,6 +811,8 @@ At this point the key is enrolled for the identity. 1. Erases the challenge value in the database to prevent re-use. 1. Replies with 200 with a fresh session token and a higher AAL e.g. AAL2 or AAL3 +[![DeviceAuthn login sequence](https://mermaid.ink/img/eyJjb2RlIjogInNlcXVlbmNlRGlhZ3JhbVxuICAgIHBhcnRpY2lwYW50IEMgYXMgQ2xpZW50IChtb2JpbGUgYXBwKVxuICAgIHBhcnRpY2lwYW50IEggYXMgRGV2aWNlIGhhcmR3YXJlIChURUUvVFBNKVxuICAgIHBhcnRpY2lwYW50IFMgYXMgS3JhdG9zIHNlcnZlclxuICAgIEMtPj5TOiBQT1NUIC9zZWxmLXNlcnZpY2UvbG9naW4vYXBpIHthYWw6IGFhbDIsIHJlZnJlc2g6IGZhbHNlfVxuICAgIFMtLT4+QzogMjAwIGxvZ2luIGZsb3cge25vbmNlfVxuICAgIEMtPj5IOiBzaWduKG5vbmNlLCBjbGllbnRfa2V5X2lkKVxuICAgIE5vdGUgcmlnaHQgb2YgSDogYmlvbWV0cmljL1BJTiBwcm9tcHQ8YnIvPnByaXZhdGUga2V5IG5ldmVyIGxlYXZlcyBoYXJkd2FyZVxuICAgIEgtLT4+QzogRUNEU0Egc2lnbmF0dXJlXG4gICAgQy0+PlM6IFBVVCAvc2VsZi1zZXJ2aWNlL2xvZ2luP2Zsb3c9Li4uIHttZXRob2Q6IGRldmljZWF1dGhuLDxici8+Y2xpZW50X2tleV9pZCwgc2lnbmF0dXJlfVxuICAgIE5vdGUgb3ZlciBTOiBWZXJpZnkgc2lnbmF0dXJlIHdpdGggc3RvcmVkIHB1YmtleTxici8+Q2hlY2sgbm8gQ0EgaW4gY2hhaW4gaXMgcmV2b2tlZDxici8+RXJhc2UgY2hhbGxlbmdlXG4gICAgUy0tPj5DOiAyMDAge3Nlc3Npb25fdG9rZW4sIGFhbDogYWFsMn0iLCAibWVybWFpZCI6IHsidGhlbWUiOiAiZGVmYXVsdCJ9fQ==)](https://mermaid.live/edit#eyJjb2RlIjogInNlcXVlbmNlRGlhZ3JhbVxuICAgIHBhcnRpY2lwYW50IEMgYXMgQ2xpZW50IChtb2JpbGUgYXBwKVxuICAgIHBhcnRpY2lwYW50IEggYXMgRGV2aWNlIGhhcmR3YXJlIChURUUvVFBNKVxuICAgIHBhcnRpY2lwYW50IFMgYXMgS3JhdG9zIHNlcnZlclxuICAgIEMtPj5TOiBQT1NUIC9zZWxmLXNlcnZpY2UvbG9naW4vYXBpIHthYWw6IGFhbDIsIHJlZnJlc2g6IGZhbHNlfVxuICAgIFMtLT4+QzogMjAwIGxvZ2luIGZsb3cge25vbmNlfVxuICAgIEMtPj5IOiBzaWduKG5vbmNlLCBjbGllbnRfa2V5X2lkKVxuICAgIE5vdGUgcmlnaHQgb2YgSDogYmlvbWV0cmljL1BJTiBwcm9tcHQ8YnIvPnByaXZhdGUga2V5IG5ldmVyIGxlYXZlcyBoYXJkd2FyZVxuICAgIEgtLT4+QzogRUNEU0Egc2lnbmF0dXJlXG4gICAgQy0+PlM6IFBVVCAvc2VsZi1zZXJ2aWNlL2xvZ2luP2Zsb3c9Li4uIHttZXRob2Q6IGRldmljZWF1dGhuLDxici8+Y2xpZW50X2tleV9pZCwgc2lnbmF0dXJlfVxuICAgIE5vdGUgb3ZlciBTOiBWZXJpZnkgc2lnbmF0dXJlIHdpdGggc3RvcmVkIHB1YmtleTxici8+Q2hlY2sgbm8gQ0EgaW4gY2hhaW4gaXMgcmV2b2tlZDxici8+RXJhc2UgY2hhbGxlbmdlXG4gICAgUy0tPj5DOiAyMDAge3Nlc3Npb25fdG9rZW4sIGFhbDogYWFsMn0iLCAibWVybWFpZCI6IHsidGhlbWUiOiAiZGVmYXVsdCJ9fQ==) + ### Key Revocation - The user can revoke a key themselves (e.g. because the device is stolen, lost, broken, etc) using the settings flow. This action From 46be2801c102f900b56eaeda424b6f5bfd0c5715 Mon Sep 17 00:00:00 2001 From: Philippe Gaultier Date: Thu, 21 May 2026 15:52:51 +0200 Subject: [PATCH 2/4] add diagram source in code comment --- docs/kratos/passwordless/08_deviceauthn.mdx | 29 +++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/docs/kratos/passwordless/08_deviceauthn.mdx b/docs/kratos/passwordless/08_deviceauthn.mdx index a3ec17ce2..e148ad423 100644 --- a/docs/kratos/passwordless/08_deviceauthn.mdx +++ b/docs/kratos/passwordless/08_deviceauthn.mdx @@ -797,6 +797,20 @@ And the Flutter code gets this result back: `iOS 26.2.1` (for example). At this point the key is enrolled for the identity. +{/* +sequenceDiagram + participant C as Client (mobile app) + participant H as Device hardware (TEE/TPM) + participant S as Kratos server + C->>S: POST /self-service/settings/api (xSessionToken) + S-->>C: 200 settings flow {nonce, existing_keys} + C->>H: generateKey(nonce) + H-->>C: {client_key_id, cert_chain} + C->>S: PUT /self-service/settings?flow=... {method: deviceauthn, add: {device_name, client_key_id, cert_chain or attestation_ios}} + Note over S: Verify cert chain vs Apple/Google root CAs
Check CRLs
Match challenge to stored nonce
Reject software/emulated keys
Store pubkey, erase challenge + S-->>C: 200 updated settings flow +*/} + [![DeviceAuthn enrollment sequence](https://mermaid.ink/img/eyJjb2RlIjogInNlcXVlbmNlRGlhZ3JhbVxuICAgIHBhcnRpY2lwYW50IEMgYXMgQ2xpZW50IChtb2JpbGUgYXBwKVxuICAgIHBhcnRpY2lwYW50IEggYXMgRGV2aWNlIGhhcmR3YXJlIChURUUvVFBNKVxuICAgIHBhcnRpY2lwYW50IFMgYXMgS3JhdG9zIHNlcnZlclxuICAgIEMtPj5TOiBQT1NUIC9zZWxmLXNlcnZpY2Uvc2V0dGluZ3MvYXBpICh4U2Vzc2lvblRva2VuKVxuICAgIFMtLT4+QzogMjAwIHNldHRpbmdzIGZsb3cge25vbmNlLCBleGlzdGluZ19rZXlzfVxuICAgIEMtPj5IOiBnZW5lcmF0ZUtleShub25jZSlcbiAgICBILS0+PkM6IHtjbGllbnRfa2V5X2lkLCBjZXJ0X2NoYWlufVxuICAgIEMtPj5TOiBQVVQgL3NlbGYtc2VydmljZS9zZXR0aW5ncz9mbG93PS4uLiB7bWV0aG9kOiBkZXZpY2VhdXRobiwgYWRkOiB7ZGV2aWNlX25hbWUsIGNsaWVudF9rZXlfaWQsIGNlcnRfY2hhaW4gb3IgYXR0ZXN0YXRpb25faW9zfX1cbiAgICBOb3RlIG92ZXIgUzogVmVyaWZ5IGNlcnQgY2hhaW4gdnMgQXBwbGUvR29vZ2xlIHJvb3QgQ0FzPGJyLz5DaGVjayBDUkxzPGJyLz5NYXRjaCBjaGFsbGVuZ2UgdG8gc3RvcmVkIG5vbmNlPGJyLz5SZWplY3Qgc29mdHdhcmUvZW11bGF0ZWQga2V5czxici8+U3RvcmUgcHVia2V5LCBlcmFzZSBjaGFsbGVuZ2VcbiAgICBTLS0+PkM6IDIwMCB1cGRhdGVkIHNldHRpbmdzIGZsb3ciLCAibWVybWFpZCI6IHsidGhlbWUiOiAiZGVmYXVsdCJ9fQ==)](https://mermaid.live/edit#eyJjb2RlIjogInNlcXVlbmNlRGlhZ3JhbVxuICAgIHBhcnRpY2lwYW50IEMgYXMgQ2xpZW50IChtb2JpbGUgYXBwKVxuICAgIHBhcnRpY2lwYW50IEggYXMgRGV2aWNlIGhhcmR3YXJlIChURUUvVFBNKVxuICAgIHBhcnRpY2lwYW50IFMgYXMgS3JhdG9zIHNlcnZlclxuICAgIEMtPj5TOiBQT1NUIC9zZWxmLXNlcnZpY2Uvc2V0dGluZ3MvYXBpICh4U2Vzc2lvblRva2VuKVxuICAgIFMtLT4+QzogMjAwIHNldHRpbmdzIGZsb3cge25vbmNlLCBleGlzdGluZ19rZXlzfVxuICAgIEMtPj5IOiBnZW5lcmF0ZUtleShub25jZSlcbiAgICBILS0+PkM6IHtjbGllbnRfa2V5X2lkLCBjZXJ0X2NoYWlufVxuICAgIEMtPj5TOiBQVVQgL3NlbGYtc2VydmljZS9zZXR0aW5ncz9mbG93PS4uLiB7bWV0aG9kOiBkZXZpY2VhdXRobiwgYWRkOiB7ZGV2aWNlX25hbWUsIGNsaWVudF9rZXlfaWQsIGNlcnRfY2hhaW4gb3IgYXR0ZXN0YXRpb25faW9zfX1cbiAgICBOb3RlIG92ZXIgUzogVmVyaWZ5IGNlcnQgY2hhaW4gdnMgQXBwbGUvR29vZ2xlIHJvb3QgQ0FzPGJyLz5DaGVjayBDUkxzPGJyLz5NYXRjaCBjaGFsbGVuZ2UgdG8gc3RvcmVkIG5vbmNlPGJyLz5SZWplY3Qgc29mdHdhcmUvZW11bGF0ZWQga2V5czxici8+U3RvcmUgcHVia2V5LCBlcmFzZSBjaGFsbGVuZ2VcbiAgICBTLS0+PkM6IDIwMCB1cGRhdGVkIHNldHRpbmdzIGZsb3ciLCAibWVybWFpZCI6IHsidGhlbWUiOiAiZGVmYXVsdCJ9fQ==) ### Proof of device enrollment @@ -811,6 +825,21 @@ At this point the key is enrolled for the identity. 1. Erases the challenge value in the database to prevent re-use. 1. Replies with 200 with a fresh session token and a higher AAL e.g. AAL2 or AAL3 +{/* +sequenceDiagram + participant C as Client (mobile app) + participant H as Device hardware (TEE/TPM) + participant S as Kratos server + C->>S: POST /self-service/login/api {aal: aal2, refresh: false} + S-->>C: 200 login flow {nonce} + C->>H: sign(nonce, client_key_id) + Note right of H: biometric/PIN prompt
private key never leaves hardware + H-->>C: ECDSA signature + C->>S: PUT /self-service/login?flow=... {method: deviceauthn,
client_key_id, signature} + Note over S: Verify signature with stored pubkey
Check no CA in chain is revoked
Erase challenge + S-->>C: 200 {session_token, aal: aal2} +*/} + [![DeviceAuthn login sequence](https://mermaid.ink/img/eyJjb2RlIjogInNlcXVlbmNlRGlhZ3JhbVxuICAgIHBhcnRpY2lwYW50IEMgYXMgQ2xpZW50IChtb2JpbGUgYXBwKVxuICAgIHBhcnRpY2lwYW50IEggYXMgRGV2aWNlIGhhcmR3YXJlIChURUUvVFBNKVxuICAgIHBhcnRpY2lwYW50IFMgYXMgS3JhdG9zIHNlcnZlclxuICAgIEMtPj5TOiBQT1NUIC9zZWxmLXNlcnZpY2UvbG9naW4vYXBpIHthYWw6IGFhbDIsIHJlZnJlc2g6IGZhbHNlfVxuICAgIFMtLT4+QzogMjAwIGxvZ2luIGZsb3cge25vbmNlfVxuICAgIEMtPj5IOiBzaWduKG5vbmNlLCBjbGllbnRfa2V5X2lkKVxuICAgIE5vdGUgcmlnaHQgb2YgSDogYmlvbWV0cmljL1BJTiBwcm9tcHQ8YnIvPnByaXZhdGUga2V5IG5ldmVyIGxlYXZlcyBoYXJkd2FyZVxuICAgIEgtLT4+QzogRUNEU0Egc2lnbmF0dXJlXG4gICAgQy0+PlM6IFBVVCAvc2VsZi1zZXJ2aWNlL2xvZ2luP2Zsb3c9Li4uIHttZXRob2Q6IGRldmljZWF1dGhuLDxici8+Y2xpZW50X2tleV9pZCwgc2lnbmF0dXJlfVxuICAgIE5vdGUgb3ZlciBTOiBWZXJpZnkgc2lnbmF0dXJlIHdpdGggc3RvcmVkIHB1YmtleTxici8+Q2hlY2sgbm8gQ0EgaW4gY2hhaW4gaXMgcmV2b2tlZDxici8+RXJhc2UgY2hhbGxlbmdlXG4gICAgUy0tPj5DOiAyMDAge3Nlc3Npb25fdG9rZW4sIGFhbDogYWFsMn0iLCAibWVybWFpZCI6IHsidGhlbWUiOiAiZGVmYXVsdCJ9fQ==)](https://mermaid.live/edit#eyJjb2RlIjogInNlcXVlbmNlRGlhZ3JhbVxuICAgIHBhcnRpY2lwYW50IEMgYXMgQ2xpZW50IChtb2JpbGUgYXBwKVxuICAgIHBhcnRpY2lwYW50IEggYXMgRGV2aWNlIGhhcmR3YXJlIChURUUvVFBNKVxuICAgIHBhcnRpY2lwYW50IFMgYXMgS3JhdG9zIHNlcnZlclxuICAgIEMtPj5TOiBQT1NUIC9zZWxmLXNlcnZpY2UvbG9naW4vYXBpIHthYWw6IGFhbDIsIHJlZnJlc2g6IGZhbHNlfVxuICAgIFMtLT4+QzogMjAwIGxvZ2luIGZsb3cge25vbmNlfVxuICAgIEMtPj5IOiBzaWduKG5vbmNlLCBjbGllbnRfa2V5X2lkKVxuICAgIE5vdGUgcmlnaHQgb2YgSDogYmlvbWV0cmljL1BJTiBwcm9tcHQ8YnIvPnByaXZhdGUga2V5IG5ldmVyIGxlYXZlcyBoYXJkd2FyZVxuICAgIEgtLT4+QzogRUNEU0Egc2lnbmF0dXJlXG4gICAgQy0+PlM6IFBVVCAvc2VsZi1zZXJ2aWNlL2xvZ2luP2Zsb3c9Li4uIHttZXRob2Q6IGRldmljZWF1dGhuLDxici8+Y2xpZW50X2tleV9pZCwgc2lnbmF0dXJlfVxuICAgIE5vdGUgb3ZlciBTOiBWZXJpZnkgc2lnbmF0dXJlIHdpdGggc3RvcmVkIHB1YmtleTxici8+Q2hlY2sgbm8gQ0EgaW4gY2hhaW4gaXMgcmV2b2tlZDxici8+RXJhc2UgY2hhbGxlbmdlXG4gICAgUy0tPj5DOiAyMDAge3Nlc3Npb25fdG9rZW4sIGFhbDogYWFsMn0iLCAibWVybWFpZCI6IHsidGhlbWUiOiAiZGVmYXVsdCJ9fQ==) ### Key Revocation From 65cc0598ccc471c6373ed45a19520c91fd5a38aa Mon Sep 17 00:00:00 2001 From: Philippe Gaultier Date: Thu, 21 May 2026 16:08:13 +0200 Subject: [PATCH 3/4] fix comment garbled by formatting --- .prettierignore | 1 + docs/kratos/passwordless/08_deviceauthn.mdx | 32 ++++++++++++++------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/.prettierignore b/.prettierignore index 268abbd13..9764e56de 100644 --- a/.prettierignore +++ b/.prettierignore @@ -17,3 +17,4 @@ vendor code-examples/sdk/typescript/src/**/*.hbs **/.dart_tool **/*.jsonc +.claude/ diff --git a/docs/kratos/passwordless/08_deviceauthn.mdx b/docs/kratos/passwordless/08_deviceauthn.mdx index e148ad423..843ca32cf 100644 --- a/docs/kratos/passwordless/08_deviceauthn.mdx +++ b/docs/kratos/passwordless/08_deviceauthn.mdx @@ -797,19 +797,24 @@ And the Flutter code gets this result back: `iOS 26.2.1` (for example). At this point the key is enrolled for the identity. -{/* +>C: 200 settings flow {nonce, existing_keys} + S-->>C: 200 settings flow (nonce, existing_keys) + C->>H: generateKey(nonce) - H-->>C: {client_key_id, cert_chain} - C->>S: PUT /self-service/settings?flow=... {method: deviceauthn, add: {device_name, client_key_id, cert_chain or attestation_ios}} + H-->>C: (client_key_id, cert_chain) + C->>S: PUT /self-service/settings?flow=... (method: deviceauthn, add: (device_name, client_key_id, cert_chain or attestation_ios)) Note over S: Verify cert chain vs Apple/Google root CAs
Check CRLs
Match challenge to stored nonce
Reject software/emulated keys
Store pubkey, erase challenge S-->>C: 200 updated settings flow -*/} + +--> [![DeviceAuthn enrollment sequence](https://mermaid.ink/img/eyJjb2RlIjogInNlcXVlbmNlRGlhZ3JhbVxuICAgIHBhcnRpY2lwYW50IEMgYXMgQ2xpZW50IChtb2JpbGUgYXBwKVxuICAgIHBhcnRpY2lwYW50IEggYXMgRGV2aWNlIGhhcmR3YXJlIChURUUvVFBNKVxuICAgIHBhcnRpY2lwYW50IFMgYXMgS3JhdG9zIHNlcnZlclxuICAgIEMtPj5TOiBQT1NUIC9zZWxmLXNlcnZpY2Uvc2V0dGluZ3MvYXBpICh4U2Vzc2lvblRva2VuKVxuICAgIFMtLT4+QzogMjAwIHNldHRpbmdzIGZsb3cge25vbmNlLCBleGlzdGluZ19rZXlzfVxuICAgIEMtPj5IOiBnZW5lcmF0ZUtleShub25jZSlcbiAgICBILS0+PkM6IHtjbGllbnRfa2V5X2lkLCBjZXJ0X2NoYWlufVxuICAgIEMtPj5TOiBQVVQgL3NlbGYtc2VydmljZS9zZXR0aW5ncz9mbG93PS4uLiB7bWV0aG9kOiBkZXZpY2VhdXRobiwgYWRkOiB7ZGV2aWNlX25hbWUsIGNsaWVudF9rZXlfaWQsIGNlcnRfY2hhaW4gb3IgYXR0ZXN0YXRpb25faW9zfX1cbiAgICBOb3RlIG92ZXIgUzogVmVyaWZ5IGNlcnQgY2hhaW4gdnMgQXBwbGUvR29vZ2xlIHJvb3QgQ0FzPGJyLz5DaGVjayBDUkxzPGJyLz5NYXRjaCBjaGFsbGVuZ2UgdG8gc3RvcmVkIG5vbmNlPGJyLz5SZWplY3Qgc29mdHdhcmUvZW11bGF0ZWQga2V5czxici8+U3RvcmUgcHVia2V5LCBlcmFzZSBjaGFsbGVuZ2VcbiAgICBTLS0+PkM6IDIwMCB1cGRhdGVkIHNldHRpbmdzIGZsb3ciLCAibWVybWFpZCI6IHsidGhlbWUiOiAiZGVmYXVsdCJ9fQ==)](https://mermaid.live/edit#eyJjb2RlIjogInNlcXVlbmNlRGlhZ3JhbVxuICAgIHBhcnRpY2lwYW50IEMgYXMgQ2xpZW50IChtb2JpbGUgYXBwKVxuICAgIHBhcnRpY2lwYW50IEggYXMgRGV2aWNlIGhhcmR3YXJlIChURUUvVFBNKVxuICAgIHBhcnRpY2lwYW50IFMgYXMgS3JhdG9zIHNlcnZlclxuICAgIEMtPj5TOiBQT1NUIC9zZWxmLXNlcnZpY2Uvc2V0dGluZ3MvYXBpICh4U2Vzc2lvblRva2VuKVxuICAgIFMtLT4+QzogMjAwIHNldHRpbmdzIGZsb3cge25vbmNlLCBleGlzdGluZ19rZXlzfVxuICAgIEMtPj5IOiBnZW5lcmF0ZUtleShub25jZSlcbiAgICBILS0+PkM6IHtjbGllbnRfa2V5X2lkLCBjZXJ0X2NoYWlufVxuICAgIEMtPj5TOiBQVVQgL3NlbGYtc2VydmljZS9zZXR0aW5ncz9mbG93PS4uLiB7bWV0aG9kOiBkZXZpY2VhdXRobiwgYWRkOiB7ZGV2aWNlX25hbWUsIGNsaWVudF9rZXlfaWQsIGNlcnRfY2hhaW4gb3IgYXR0ZXN0YXRpb25faW9zfX1cbiAgICBOb3RlIG92ZXIgUzogVmVyaWZ5IGNlcnQgY2hhaW4gdnMgQXBwbGUvR29vZ2xlIHJvb3QgQ0FzPGJyLz5DaGVjayBDUkxzPGJyLz5NYXRjaCBjaGFsbGVuZ2UgdG8gc3RvcmVkIG5vbmNlPGJyLz5SZWplY3Qgc29mdHdhcmUvZW11bGF0ZWQga2V5czxici8+U3RvcmUgcHVia2V5LCBlcmFzZSBjaGFsbGVuZ2VcbiAgICBTLS0+PkM6IDIwMCB1cGRhdGVkIHNldHRpbmdzIGZsb3ciLCAibWVybWFpZCI6IHsidGhlbWUiOiAiZGVmYXVsdCJ9fQ==) @@ -825,20 +830,25 @@ sequenceDiagram 1. Erases the challenge value in the database to prevent re-use. 1. Replies with 200 with a fresh session token and a higher AAL e.g. AAL2 or AAL3 -{/* +>C: 200 login flow {nonce} + C->>S: POST /self-service/login/api (aal: aal2, refresh: false) + S-->>C: 200 login flow (nonce) + C->>H: sign(nonce, client_key_id) Note right of H: biometric/PIN prompt
private key never leaves hardware H-->>C: ECDSA signature - C->>S: PUT /self-service/login?flow=... {method: deviceauthn,
client_key_id, signature} + C->>S: PUT /self-service/login?flow=... (method: deviceauthn,
client_key_id, signature) Note over S: Verify signature with stored pubkey
Check no CA in chain is revoked
Erase challenge - S-->>C: 200 {session_token, aal: aal2} -*/} + S-->>C: 200 (session_token, aal: aal2) + +--> [![DeviceAuthn login sequence](https://mermaid.ink/img/eyJjb2RlIjogInNlcXVlbmNlRGlhZ3JhbVxuICAgIHBhcnRpY2lwYW50IEMgYXMgQ2xpZW50IChtb2JpbGUgYXBwKVxuICAgIHBhcnRpY2lwYW50IEggYXMgRGV2aWNlIGhhcmR3YXJlIChURUUvVFBNKVxuICAgIHBhcnRpY2lwYW50IFMgYXMgS3JhdG9zIHNlcnZlclxuICAgIEMtPj5TOiBQT1NUIC9zZWxmLXNlcnZpY2UvbG9naW4vYXBpIHthYWw6IGFhbDIsIHJlZnJlc2g6IGZhbHNlfVxuICAgIFMtLT4+QzogMjAwIGxvZ2luIGZsb3cge25vbmNlfVxuICAgIEMtPj5IOiBzaWduKG5vbmNlLCBjbGllbnRfa2V5X2lkKVxuICAgIE5vdGUgcmlnaHQgb2YgSDogYmlvbWV0cmljL1BJTiBwcm9tcHQ8YnIvPnByaXZhdGUga2V5IG5ldmVyIGxlYXZlcyBoYXJkd2FyZVxuICAgIEgtLT4+QzogRUNEU0Egc2lnbmF0dXJlXG4gICAgQy0+PlM6IFBVVCAvc2VsZi1zZXJ2aWNlL2xvZ2luP2Zsb3c9Li4uIHttZXRob2Q6IGRldmljZWF1dGhuLDxici8+Y2xpZW50X2tleV9pZCwgc2lnbmF0dXJlfVxuICAgIE5vdGUgb3ZlciBTOiBWZXJpZnkgc2lnbmF0dXJlIHdpdGggc3RvcmVkIHB1YmtleTxici8+Q2hlY2sgbm8gQ0EgaW4gY2hhaW4gaXMgcmV2b2tlZDxici8+RXJhc2UgY2hhbGxlbmdlXG4gICAgUy0tPj5DOiAyMDAge3Nlc3Npb25fdG9rZW4sIGFhbDogYWFsMn0iLCAibWVybWFpZCI6IHsidGhlbWUiOiAiZGVmYXVsdCJ9fQ==)](https://mermaid.live/edit#eyJjb2RlIjogInNlcXVlbmNlRGlhZ3JhbVxuICAgIHBhcnRpY2lwYW50IEMgYXMgQ2xpZW50IChtb2JpbGUgYXBwKVxuICAgIHBhcnRpY2lwYW50IEggYXMgRGV2aWNlIGhhcmR3YXJlIChURUUvVFBNKVxuICAgIHBhcnRpY2lwYW50IFMgYXMgS3JhdG9zIHNlcnZlclxuICAgIEMtPj5TOiBQT1NUIC9zZWxmLXNlcnZpY2UvbG9naW4vYXBpIHthYWw6IGFhbDIsIHJlZnJlc2g6IGZhbHNlfVxuICAgIFMtLT4+QzogMjAwIGxvZ2luIGZsb3cge25vbmNlfVxuICAgIEMtPj5IOiBzaWduKG5vbmNlLCBjbGllbnRfa2V5X2lkKVxuICAgIE5vdGUgcmlnaHQgb2YgSDogYmlvbWV0cmljL1BJTiBwcm9tcHQ8YnIvPnByaXZhdGUga2V5IG5ldmVyIGxlYXZlcyBoYXJkd2FyZVxuICAgIEgtLT4+QzogRUNEU0Egc2lnbmF0dXJlXG4gICAgQy0+PlM6IFBVVCAvc2VsZi1zZXJ2aWNlL2xvZ2luP2Zsb3c9Li4uIHttZXRob2Q6IGRldmljZWF1dGhuLDxici8+Y2xpZW50X2tleV9pZCwgc2lnbmF0dXJlfVxuICAgIE5vdGUgb3ZlciBTOiBWZXJpZnkgc2lnbmF0dXJlIHdpdGggc3RvcmVkIHB1YmtleTxici8+Q2hlY2sgbm8gQ0EgaW4gY2hhaW4gaXMgcmV2b2tlZDxici8+RXJhc2UgY2hhbGxlbmdlXG4gICAgUy0tPj5DOiAyMDAge3Nlc3Npb25fdG9rZW4sIGFhbDogYWFsMn0iLCAibWVybWFpZCI6IHsidGhlbWUiOiAiZGVmYXVsdCJ9fQ==) From 811459a62e72460a837844af3d7630e1c0028e96 Mon Sep 17 00:00:00 2001 From: Philippe Gaultier Date: Thu, 21 May 2026 16:12:54 +0200 Subject: [PATCH 4/4] rm garbled comments --- docs/kratos/passwordless/08_deviceauthn.mdx | 39 --------------------- 1 file changed, 39 deletions(-) diff --git a/docs/kratos/passwordless/08_deviceauthn.mdx b/docs/kratos/passwordless/08_deviceauthn.mdx index 843ca32cf..a3ec17ce2 100644 --- a/docs/kratos/passwordless/08_deviceauthn.mdx +++ b/docs/kratos/passwordless/08_deviceauthn.mdx @@ -797,25 +797,6 @@ And the Flutter code gets this result back: `iOS 26.2.1` (for example). At this point the key is enrolled for the identity. ->C: 200 settings flow (nonce, existing_keys) - - C->>H: generateKey(nonce) - H-->>C: (client_key_id, cert_chain) - C->>S: PUT /self-service/settings?flow=... (method: deviceauthn, add: (device_name, client_key_id, cert_chain or attestation_ios)) - Note over S: Verify cert chain vs Apple/Google root CAs
Check CRLs
Match challenge to stored nonce
Reject software/emulated keys
Store pubkey, erase challenge - S-->>C: 200 updated settings flow - ---> - [![DeviceAuthn enrollment sequence](https://mermaid.ink/img/eyJjb2RlIjogInNlcXVlbmNlRGlhZ3JhbVxuICAgIHBhcnRpY2lwYW50IEMgYXMgQ2xpZW50IChtb2JpbGUgYXBwKVxuICAgIHBhcnRpY2lwYW50IEggYXMgRGV2aWNlIGhhcmR3YXJlIChURUUvVFBNKVxuICAgIHBhcnRpY2lwYW50IFMgYXMgS3JhdG9zIHNlcnZlclxuICAgIEMtPj5TOiBQT1NUIC9zZWxmLXNlcnZpY2Uvc2V0dGluZ3MvYXBpICh4U2Vzc2lvblRva2VuKVxuICAgIFMtLT4+QzogMjAwIHNldHRpbmdzIGZsb3cge25vbmNlLCBleGlzdGluZ19rZXlzfVxuICAgIEMtPj5IOiBnZW5lcmF0ZUtleShub25jZSlcbiAgICBILS0+PkM6IHtjbGllbnRfa2V5X2lkLCBjZXJ0X2NoYWlufVxuICAgIEMtPj5TOiBQVVQgL3NlbGYtc2VydmljZS9zZXR0aW5ncz9mbG93PS4uLiB7bWV0aG9kOiBkZXZpY2VhdXRobiwgYWRkOiB7ZGV2aWNlX25hbWUsIGNsaWVudF9rZXlfaWQsIGNlcnRfY2hhaW4gb3IgYXR0ZXN0YXRpb25faW9zfX1cbiAgICBOb3RlIG92ZXIgUzogVmVyaWZ5IGNlcnQgY2hhaW4gdnMgQXBwbGUvR29vZ2xlIHJvb3QgQ0FzPGJyLz5DaGVjayBDUkxzPGJyLz5NYXRjaCBjaGFsbGVuZ2UgdG8gc3RvcmVkIG5vbmNlPGJyLz5SZWplY3Qgc29mdHdhcmUvZW11bGF0ZWQga2V5czxici8+U3RvcmUgcHVia2V5LCBlcmFzZSBjaGFsbGVuZ2VcbiAgICBTLS0+PkM6IDIwMCB1cGRhdGVkIHNldHRpbmdzIGZsb3ciLCAibWVybWFpZCI6IHsidGhlbWUiOiAiZGVmYXVsdCJ9fQ==)](https://mermaid.live/edit#eyJjb2RlIjogInNlcXVlbmNlRGlhZ3JhbVxuICAgIHBhcnRpY2lwYW50IEMgYXMgQ2xpZW50IChtb2JpbGUgYXBwKVxuICAgIHBhcnRpY2lwYW50IEggYXMgRGV2aWNlIGhhcmR3YXJlIChURUUvVFBNKVxuICAgIHBhcnRpY2lwYW50IFMgYXMgS3JhdG9zIHNlcnZlclxuICAgIEMtPj5TOiBQT1NUIC9zZWxmLXNlcnZpY2Uvc2V0dGluZ3MvYXBpICh4U2Vzc2lvblRva2VuKVxuICAgIFMtLT4+QzogMjAwIHNldHRpbmdzIGZsb3cge25vbmNlLCBleGlzdGluZ19rZXlzfVxuICAgIEMtPj5IOiBnZW5lcmF0ZUtleShub25jZSlcbiAgICBILS0+PkM6IHtjbGllbnRfa2V5X2lkLCBjZXJ0X2NoYWlufVxuICAgIEMtPj5TOiBQVVQgL3NlbGYtc2VydmljZS9zZXR0aW5ncz9mbG93PS4uLiB7bWV0aG9kOiBkZXZpY2VhdXRobiwgYWRkOiB7ZGV2aWNlX25hbWUsIGNsaWVudF9rZXlfaWQsIGNlcnRfY2hhaW4gb3IgYXR0ZXN0YXRpb25faW9zfX1cbiAgICBOb3RlIG92ZXIgUzogVmVyaWZ5IGNlcnQgY2hhaW4gdnMgQXBwbGUvR29vZ2xlIHJvb3QgQ0FzPGJyLz5DaGVjayBDUkxzPGJyLz5NYXRjaCBjaGFsbGVuZ2UgdG8gc3RvcmVkIG5vbmNlPGJyLz5SZWplY3Qgc29mdHdhcmUvZW11bGF0ZWQga2V5czxici8+U3RvcmUgcHVia2V5LCBlcmFzZSBjaGFsbGVuZ2VcbiAgICBTLS0+PkM6IDIwMCB1cGRhdGVkIHNldHRpbmdzIGZsb3ciLCAibWVybWFpZCI6IHsidGhlbWUiOiAiZGVmYXVsdCJ9fQ==) ### Proof of device enrollment @@ -830,26 +811,6 @@ sequenceDiagram 1. Erases the challenge value in the database to prevent re-use. 1. Replies with 200 with a fresh session token and a higher AAL e.g. AAL2 or AAL3 ->C: 200 login flow (nonce) - - C->>H: sign(nonce, client_key_id) - Note right of H: biometric/PIN prompt
private key never leaves hardware - H-->>C: ECDSA signature - C->>S: PUT /self-service/login?flow=... (method: deviceauthn,
client_key_id, signature) - Note over S: Verify signature with stored pubkey
Check no CA in chain is revoked
Erase challenge - S-->>C: 200 (session_token, aal: aal2) - ---> - [![DeviceAuthn login sequence](https://mermaid.ink/img/eyJjb2RlIjogInNlcXVlbmNlRGlhZ3JhbVxuICAgIHBhcnRpY2lwYW50IEMgYXMgQ2xpZW50IChtb2JpbGUgYXBwKVxuICAgIHBhcnRpY2lwYW50IEggYXMgRGV2aWNlIGhhcmR3YXJlIChURUUvVFBNKVxuICAgIHBhcnRpY2lwYW50IFMgYXMgS3JhdG9zIHNlcnZlclxuICAgIEMtPj5TOiBQT1NUIC9zZWxmLXNlcnZpY2UvbG9naW4vYXBpIHthYWw6IGFhbDIsIHJlZnJlc2g6IGZhbHNlfVxuICAgIFMtLT4+QzogMjAwIGxvZ2luIGZsb3cge25vbmNlfVxuICAgIEMtPj5IOiBzaWduKG5vbmNlLCBjbGllbnRfa2V5X2lkKVxuICAgIE5vdGUgcmlnaHQgb2YgSDogYmlvbWV0cmljL1BJTiBwcm9tcHQ8YnIvPnByaXZhdGUga2V5IG5ldmVyIGxlYXZlcyBoYXJkd2FyZVxuICAgIEgtLT4+QzogRUNEU0Egc2lnbmF0dXJlXG4gICAgQy0+PlM6IFBVVCAvc2VsZi1zZXJ2aWNlL2xvZ2luP2Zsb3c9Li4uIHttZXRob2Q6IGRldmljZWF1dGhuLDxici8+Y2xpZW50X2tleV9pZCwgc2lnbmF0dXJlfVxuICAgIE5vdGUgb3ZlciBTOiBWZXJpZnkgc2lnbmF0dXJlIHdpdGggc3RvcmVkIHB1YmtleTxici8+Q2hlY2sgbm8gQ0EgaW4gY2hhaW4gaXMgcmV2b2tlZDxici8+RXJhc2UgY2hhbGxlbmdlXG4gICAgUy0tPj5DOiAyMDAge3Nlc3Npb25fdG9rZW4sIGFhbDogYWFsMn0iLCAibWVybWFpZCI6IHsidGhlbWUiOiAiZGVmYXVsdCJ9fQ==)](https://mermaid.live/edit#eyJjb2RlIjogInNlcXVlbmNlRGlhZ3JhbVxuICAgIHBhcnRpY2lwYW50IEMgYXMgQ2xpZW50IChtb2JpbGUgYXBwKVxuICAgIHBhcnRpY2lwYW50IEggYXMgRGV2aWNlIGhhcmR3YXJlIChURUUvVFBNKVxuICAgIHBhcnRpY2lwYW50IFMgYXMgS3JhdG9zIHNlcnZlclxuICAgIEMtPj5TOiBQT1NUIC9zZWxmLXNlcnZpY2UvbG9naW4vYXBpIHthYWw6IGFhbDIsIHJlZnJlc2g6IGZhbHNlfVxuICAgIFMtLT4+QzogMjAwIGxvZ2luIGZsb3cge25vbmNlfVxuICAgIEMtPj5IOiBzaWduKG5vbmNlLCBjbGllbnRfa2V5X2lkKVxuICAgIE5vdGUgcmlnaHQgb2YgSDogYmlvbWV0cmljL1BJTiBwcm9tcHQ8YnIvPnByaXZhdGUga2V5IG5ldmVyIGxlYXZlcyBoYXJkd2FyZVxuICAgIEgtLT4+QzogRUNEU0Egc2lnbmF0dXJlXG4gICAgQy0+PlM6IFBVVCAvc2VsZi1zZXJ2aWNlL2xvZ2luP2Zsb3c9Li4uIHttZXRob2Q6IGRldmljZWF1dGhuLDxici8+Y2xpZW50X2tleV9pZCwgc2lnbmF0dXJlfVxuICAgIE5vdGUgb3ZlciBTOiBWZXJpZnkgc2lnbmF0dXJlIHdpdGggc3RvcmVkIHB1YmtleTxici8+Q2hlY2sgbm8gQ0EgaW4gY2hhaW4gaXMgcmV2b2tlZDxici8+RXJhc2UgY2hhbGxlbmdlXG4gICAgUy0tPj5DOiAyMDAge3Nlc3Npb25fdG9rZW4sIGFhbDogYWFsMn0iLCAibWVybWFpZCI6IHsidGhlbWUiOiAiZGVmYXVsdCJ9fQ==) ### Key Revocation