From 4536462261b85c6ef7c43e7ae61419159acaa67a Mon Sep 17 00:00:00 2001 From: jhickmanit Date: Tue, 21 Apr 2026 08:35:41 -0700 Subject: [PATCH 1/4] docs(kratos): document passkey advanced configuration options Add an 'Advanced configuration' section under the dedicated passkey strategy that documents: - authenticator_selection (attachment, require_resident_key, user_verification) - attestation (preference, allow_none, allow_self, allow_untrusted) - timeouts (registration, login) Include a warning admonition explaining that disabling attestation.allow_none rejects most consumer passkeys, and add a three-tab example (Ory CLI, Ory Network, self-hosted Kratos) showing cross-platform attachment with required user verification. --- docs/kratos/passwordless/05_passkeys.mdx | 75 ++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/docs/kratos/passwordless/05_passkeys.mdx b/docs/kratos/passwordless/05_passkeys.mdx index 6d2dcad5c1..c21774f313 100644 --- a/docs/kratos/passwordless/05_passkeys.mdx +++ b/docs/kratos/passwordless/05_passkeys.mdx @@ -111,6 +111,81 @@ Alternatively, use the Ory CLI to enable the passkey strategy: ``` +### Advanced configuration + +The passkey strategy exposes additional options that control the WebAuthn ceremony and post-registration policy. All options are +optional. Defaults match the behavior before these options were introduced, so existing deployments do not need to change +anything. + +| Option | Type | Default | What it controls | +| ---------------------------------------------- | -------- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | +| `authenticator_selection.attachment` | string | `"platform"` | Which authenticators are eligible: `"platform"` (Touch ID, Windows Hello), `"cross-platform"` (security keys), or `""` for no preference. | +| `authenticator_selection.require_resident_key` | boolean | `true` | Whether the authenticator must create a client-side discoverable credential. | +| `authenticator_selection.user_verification` | string | `"preferred"` | Whether biometrics or a PIN are required: `"required"`, `"preferred"`, or `"discouraged"`. | +| `attestation.preference` | string | `"none"` | Attestation conveyance preference sent to the authenticator: `"none"`, `"indirect"`, `"direct"`, or `"enterprise"`. | +| `attestation.allow_none` | boolean | `true` | Accept passkeys that provide no attestation statement. Most consumer passkeys, including iOS, use none attestation. | +| `attestation.allow_self` | boolean | `true` | Accept passkeys that provide a self-signed attestation statement with no external certificate authority. | +| `attestation.allow_untrusted` | boolean | `true` | Accept passkeys whose attestation certificate chain has no trusted root. | +| `timeouts.registration` | duration | library default (5m) | Timeout for the registration ceremony. Use Go duration format, for example `"60s"` or `"5m"`. | +| `timeouts.login` | duration | library default (5m) | Timeout for the login ceremony. Use Go duration format. | + +:::warning + +Disabling `attestation.allow_none` rejects most consumer passkeys. iOS does not support attestation at all, and Android and +Windows support it inconsistently. Only restrict attestation if your deployment requires attested authenticators, such as +FIDO-certified security keys in a regulated environment. The default configuration allows all attestation types so that any +standards-compliant passkey can register. + +::: + +The following example configures cross-platform authenticators (such as a HID token or YubiKey) with required user verification: + +```mdx-code-block + + + {`ory patch identity-config \\ + --add '/selfservice/methods/passkey/config/authenticator_selection/attachment="cross-platform"' \\ + --add '/selfservice/methods/passkey/config/authenticator_selection/user_verification="required"' +`} + + + + {`selfservice: + methods: + passkey: + enabled: true + config: + authenticator_selection: + attachment: cross-platform + user_verification: required`} + + + {`selfservice: + methods: + passkey: + enabled: true + config: + rp: + display_name: Your Application name + id: localhost + origins: + - http://localhost:4455 + authenticator_selection: + attachment: cross-platform + require_resident_key: true + user_verification: required + attestation: + preference: none + allow_none: true + allow_self: true + allow_untrusted: true + timeouts: + registration: 5m + login: 5m`} + + +``` + ### Identity schema If you want to use a custom identity schema, you must define which field of the identity schema is the display name for the From 9a98779525cf0d761103d4721984e3671e2680db Mon Sep 17 00:00:00 2001 From: jhickmanit Date: Wed, 22 Apr 2026 10:14:15 -0700 Subject: [PATCH 2/4] docs: update passkey options to match final Kratos API The Kratos PR moved to a simpler API shape after review: - resident_key enum replaces the require_resident_key boolean (values: required, preferred, discouraged; default required) - attestation.policy enum replaces the three allow_* booleans (values: allow_untrusted, allow_self, allow_none; default allow_untrusted) - authenticator_selection.attachment no longer defaults to "platform"; omit it to accept either platform or cross-platform authenticators Rewrite the warning admonition to match the new policy semantics and note that Kratos does not verify attestation certificate chains today, so "allow_self" and "allow_none" are opt-in stricter stances rather than cryptographic validation. Update the self-hosted example to use the new field names. --- docs/kratos/passwordless/05_passkeys.mdx | 43 ++++++++++++------------ 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/docs/kratos/passwordless/05_passkeys.mdx b/docs/kratos/passwordless/05_passkeys.mdx index c21774f313..c7b11e0698 100644 --- a/docs/kratos/passwordless/05_passkeys.mdx +++ b/docs/kratos/passwordless/05_passkeys.mdx @@ -114,27 +114,28 @@ Alternatively, use the Ory CLI to enable the passkey strategy: ### Advanced configuration The passkey strategy exposes additional options that control the WebAuthn ceremony and post-registration policy. All options are -optional. Defaults match the behavior before these options were introduced, so existing deployments do not need to change -anything. - -| Option | Type | Default | What it controls | -| ---------------------------------------------- | -------- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | -| `authenticator_selection.attachment` | string | `"platform"` | Which authenticators are eligible: `"platform"` (Touch ID, Windows Hello), `"cross-platform"` (security keys), or `""` for no preference. | -| `authenticator_selection.require_resident_key` | boolean | `true` | Whether the authenticator must create a client-side discoverable credential. | -| `authenticator_selection.user_verification` | string | `"preferred"` | Whether biometrics or a PIN are required: `"required"`, `"preferred"`, or `"discouraged"`. | -| `attestation.preference` | string | `"none"` | Attestation conveyance preference sent to the authenticator: `"none"`, `"indirect"`, `"direct"`, or `"enterprise"`. | -| `attestation.allow_none` | boolean | `true` | Accept passkeys that provide no attestation statement. Most consumer passkeys, including iOS, use none attestation. | -| `attestation.allow_self` | boolean | `true` | Accept passkeys that provide a self-signed attestation statement with no external certificate authority. | -| `attestation.allow_untrusted` | boolean | `true` | Accept passkeys whose attestation certificate chain has no trusted root. | -| `timeouts.registration` | duration | library default (5m) | Timeout for the registration ceremony. Use Go duration format, for example `"60s"` or `"5m"`. | -| `timeouts.login` | duration | library default (5m) | Timeout for the login ceremony. Use Go duration format. | +optional. Defaults accept every standards-compliant passkey, so existing deployments do not need to change anything. + +| Option | Type | Default | What it controls | +| ------------------------------------------- | -------- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `authenticator_selection.attachment` | string | _unset_ | Restricts eligible authenticators by attachment modality: `"platform"` (Touch ID, Windows Hello) or `"cross-platform"` (HID tokens, YubiKeys). Omit this field to accept either type. | +| `authenticator_selection.resident_key` | string | `"required"` | Whether the authenticator must create a client-side discoverable credential: `"required"`, `"preferred"`, or `"discouraged"`. | +| `authenticator_selection.user_verification` | string | `"preferred"` | Whether biometrics or a PIN are required: `"required"`, `"preferred"`, or `"discouraged"`. | +| `attestation.preference` | string | `"none"` | Attestation conveyance preference sent to the authenticator: `"none"`, `"indirect"`, `"direct"`, or `"enterprise"`. | +| `attestation.policy` | string | `"allow_untrusted"` | Which attestation types Kratos accepts after registration: `"allow_untrusted"` accepts any attestation, `"allow_self"` rejects credentials with unverifiable certificate chains, and `"allow_none"` only accepts credentials without an attestation statement. | +| `timeouts.registration` | duration | library default (5m) | Timeout for the registration ceremony. Use Go duration format, for example `"60s"` or `"5m"`. | +| `timeouts.login` | duration | library default (5m) | Timeout for the login ceremony. Use Go duration format. | :::warning -Disabling `attestation.allow_none` rejects most consumer passkeys. iOS does not support attestation at all, and Android and -Windows support it inconsistently. Only restrict attestation if your deployment requires attested authenticators, such as -FIDO-certified security keys in a regulated environment. The default configuration allows all attestation types so that any -standards-compliant passkey can register. +Setting `attestation.policy` to a value stricter than `"allow_untrusted"` rejects most consumer passkeys. iOS, Android, and most +password managers return no attestation statement by design, which the `"allow_none"` policy still accepts — but any +authenticator that does provide an attestation certificate chain is rejected under `"allow_self"`. Only restrict the policy if +your deployment has a clear requirement for attested authenticators. + +Kratos does not currently verify attestation certificate chains against a trust anchor (for example, the FIDO Metadata +Service). The `"allow_self"` and `"allow_none"` values are opt-in stricter stances, not cryptographic validation of +authenticator provenance. ::: @@ -172,13 +173,11 @@ The following example configures cross-platform authenticators (such as a HID to - http://localhost:4455 authenticator_selection: attachment: cross-platform - require_resident_key: true + resident_key: required user_verification: required attestation: preference: none - allow_none: true - allow_self: true - allow_untrusted: true + policy: allow_untrusted timeouts: registration: 5m login: 5m`} From 7e273fe5960102b9ddf72f6e1a8f6a146b5984e6 Mon Sep 17 00:00:00 2001 From: jhickmanit Date: Wed, 22 Apr 2026 10:15:15 -0700 Subject: [PATCH 3/4] docs: prettier --- docs/kratos/passwordless/05_passkeys.mdx | 28 ++++++++++++------------ 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/kratos/passwordless/05_passkeys.mdx b/docs/kratos/passwordless/05_passkeys.mdx index c7b11e0698..fcbe700182 100644 --- a/docs/kratos/passwordless/05_passkeys.mdx +++ b/docs/kratos/passwordless/05_passkeys.mdx @@ -116,26 +116,26 @@ Alternatively, use the Ory CLI to enable the passkey strategy: The passkey strategy exposes additional options that control the WebAuthn ceremony and post-registration policy. All options are optional. Defaults accept every standards-compliant passkey, so existing deployments do not need to change anything. -| Option | Type | Default | What it controls | -| ------------------------------------------- | -------- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `authenticator_selection.attachment` | string | _unset_ | Restricts eligible authenticators by attachment modality: `"platform"` (Touch ID, Windows Hello) or `"cross-platform"` (HID tokens, YubiKeys). Omit this field to accept either type. | -| `authenticator_selection.resident_key` | string | `"required"` | Whether the authenticator must create a client-side discoverable credential: `"required"`, `"preferred"`, or `"discouraged"`. | -| `authenticator_selection.user_verification` | string | `"preferred"` | Whether biometrics or a PIN are required: `"required"`, `"preferred"`, or `"discouraged"`. | -| `attestation.preference` | string | `"none"` | Attestation conveyance preference sent to the authenticator: `"none"`, `"indirect"`, `"direct"`, or `"enterprise"`. | +| Option | Type | Default | What it controls | +| ------------------------------------------- | -------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `authenticator_selection.attachment` | string | _unset_ | Restricts eligible authenticators by attachment modality: `"platform"` (Touch ID, Windows Hello) or `"cross-platform"` (HID tokens, YubiKeys). Omit this field to accept either type. | +| `authenticator_selection.resident_key` | string | `"required"` | Whether the authenticator must create a client-side discoverable credential: `"required"`, `"preferred"`, or `"discouraged"`. | +| `authenticator_selection.user_verification` | string | `"preferred"` | Whether biometrics or a PIN are required: `"required"`, `"preferred"`, or `"discouraged"`. | +| `attestation.preference` | string | `"none"` | Attestation conveyance preference sent to the authenticator: `"none"`, `"indirect"`, `"direct"`, or `"enterprise"`. | | `attestation.policy` | string | `"allow_untrusted"` | Which attestation types Kratos accepts after registration: `"allow_untrusted"` accepts any attestation, `"allow_self"` rejects credentials with unverifiable certificate chains, and `"allow_none"` only accepts credentials without an attestation statement. | -| `timeouts.registration` | duration | library default (5m) | Timeout for the registration ceremony. Use Go duration format, for example `"60s"` or `"5m"`. | -| `timeouts.login` | duration | library default (5m) | Timeout for the login ceremony. Use Go duration format. | +| `timeouts.registration` | duration | library default (5m) | Timeout for the registration ceremony. Use Go duration format, for example `"60s"` or `"5m"`. | +| `timeouts.login` | duration | library default (5m) | Timeout for the login ceremony. Use Go duration format. | :::warning Setting `attestation.policy` to a value stricter than `"allow_untrusted"` rejects most consumer passkeys. iOS, Android, and most -password managers return no attestation statement by design, which the `"allow_none"` policy still accepts — but any -authenticator that does provide an attestation certificate chain is rejected under `"allow_self"`. Only restrict the policy if -your deployment has a clear requirement for attested authenticators. +password managers return no attestation statement by design, which the `"allow_none"` policy still accepts — but any authenticator +that does provide an attestation certificate chain is rejected under `"allow_self"`. Only restrict the policy if your deployment +has a clear requirement for attested authenticators. -Kratos does not currently verify attestation certificate chains against a trust anchor (for example, the FIDO Metadata -Service). The `"allow_self"` and `"allow_none"` values are opt-in stricter stances, not cryptographic validation of -authenticator provenance. +Kratos does not currently verify attestation certificate chains against a trust anchor (for example, the FIDO Metadata Service). +The `"allow_self"` and `"allow_none"` values are opt-in stricter stances, not cryptographic validation of authenticator +provenance. ::: From e17e24e97505325193a30b3563153265ad4f5cce Mon Sep 17 00:00:00 2001 From: jhickmanit Date: Fri, 24 Apr 2026 13:24:53 -0700 Subject: [PATCH 4/4] docs: drop passkey attestation.policy section Policy knob was removed from the Kratos PR because Kratos has no trust-anchor verification, so strict policy levels did not provide cryptographic validation. Docs now only describe the ceremony options that shipped: authenticator_selection, attestation.preference, timeouts. --- docs/kratos/passwordless/05_passkeys.mdx | 37 +++++++----------------- 1 file changed, 11 insertions(+), 26 deletions(-) diff --git a/docs/kratos/passwordless/05_passkeys.mdx b/docs/kratos/passwordless/05_passkeys.mdx index fcbe700182..469045f952 100644 --- a/docs/kratos/passwordless/05_passkeys.mdx +++ b/docs/kratos/passwordless/05_passkeys.mdx @@ -113,31 +113,17 @@ Alternatively, use the Ory CLI to enable the passkey strategy: ### Advanced configuration -The passkey strategy exposes additional options that control the WebAuthn ceremony and post-registration policy. All options are -optional. Defaults accept every standards-compliant passkey, so existing deployments do not need to change anything. - -| Option | Type | Default | What it controls | -| ------------------------------------------- | -------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `authenticator_selection.attachment` | string | _unset_ | Restricts eligible authenticators by attachment modality: `"platform"` (Touch ID, Windows Hello) or `"cross-platform"` (HID tokens, YubiKeys). Omit this field to accept either type. | -| `authenticator_selection.resident_key` | string | `"required"` | Whether the authenticator must create a client-side discoverable credential: `"required"`, `"preferred"`, or `"discouraged"`. | -| `authenticator_selection.user_verification` | string | `"preferred"` | Whether biometrics or a PIN are required: `"required"`, `"preferred"`, or `"discouraged"`. | -| `attestation.preference` | string | `"none"` | Attestation conveyance preference sent to the authenticator: `"none"`, `"indirect"`, `"direct"`, or `"enterprise"`. | -| `attestation.policy` | string | `"allow_untrusted"` | Which attestation types Kratos accepts after registration: `"allow_untrusted"` accepts any attestation, `"allow_self"` rejects credentials with unverifiable certificate chains, and `"allow_none"` only accepts credentials without an attestation statement. | -| `timeouts.registration` | duration | library default (5m) | Timeout for the registration ceremony. Use Go duration format, for example `"60s"` or `"5m"`. | -| `timeouts.login` | duration | library default (5m) | Timeout for the login ceremony. Use Go duration format. | - -:::warning - -Setting `attestation.policy` to a value stricter than `"allow_untrusted"` rejects most consumer passkeys. iOS, Android, and most -password managers return no attestation statement by design, which the `"allow_none"` policy still accepts — but any authenticator -that does provide an attestation certificate chain is rejected under `"allow_self"`. Only restrict the policy if your deployment -has a clear requirement for attested authenticators. - -Kratos does not currently verify attestation certificate chains against a trust anchor (for example, the FIDO Metadata Service). -The `"allow_self"` and `"allow_none"` values are opt-in stricter stances, not cryptographic validation of authenticator -provenance. - -::: +The passkey strategy exposes additional options that control the WebAuthn ceremony. All options are optional. Defaults accept +every standards-compliant passkey, so existing deployments do not need to change anything. + +| Option | Type | Default | What it controls | +| ------------------------------------------- | -------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `authenticator_selection.attachment` | string | _unset_ | Restricts eligible authenticators by attachment modality: `"platform"` (Touch ID, Windows Hello) or `"cross-platform"` (HID tokens, YubiKeys). Omit this field to accept either type. | +| `authenticator_selection.resident_key` | string | `"required"` | Whether the authenticator must create a client-side discoverable credential: `"required"`, `"preferred"`, or `"discouraged"`. | +| `authenticator_selection.user_verification` | string | `"preferred"` | Whether biometrics or a PIN are required: `"required"`, `"preferred"`, or `"discouraged"`. | +| `attestation.preference` | string | `"none"` | Attestation conveyance preference sent to the authenticator: `"none"`, `"indirect"`, `"direct"`, or `"enterprise"`. | +| `timeouts.registration` | duration | library default (5m) | Timeout for the registration ceremony. Use Go duration format, for example `"60s"` or `"5m"`. | +| `timeouts.login` | duration | library default (5m) | Timeout for the login ceremony. Use Go duration format. | The following example configures cross-platform authenticators (such as a HID token or YubiKey) with required user verification: @@ -177,7 +163,6 @@ The following example configures cross-platform authenticators (such as a HID to user_verification: required attestation: preference: none - policy: allow_untrusted timeouts: registration: 5m login: 5m`}