Skip to content

Commit 8b555f3

Browse files
committed
docs: document MFA trusted devices
1 parent 49ebb19 commit 8b555f3

6 files changed

Lines changed: 167 additions & 1 deletion

File tree

docs/developers/audit-logs/event-types.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ Feel free to [contact us](https://logto.io/contact) if you’d like to share you
134134
| Interaction.SignIn.Verification.Totp.Submit | Verify TOTP verification code |
135135
| Interaction.SignIn.Verification.Webauthn.Create | Create WebAuthn authentication |
136136
| Interaction.SignIn.Verification.WebAuthn.Submit | Verify WebAuthn authentication |
137+
| TrustedDevice.Created | Create a trusted-device credential |
138+
| TrustedDevice.Used | Use a trusted device to fulfill sign-in MFA |
137139

138140
## SAML application \{#saml-application}
139141

docs/developers/webhooks/events.mdx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,15 @@ This guide list the different Logto webhook events and explains when each event
7171
| OrganizationScope.Deleted | A organization permission is deleted. |
7272
| OrganizationScope.Data.Updated | A organization permission's data is updated, e.g., organization permission description. |
7373

74+
### Trusted device \{#trusted-device}
75+
76+
| Event type | Description |
77+
| --------------------- | --------------------------------------------------------------------------------- |
78+
| TrustedDevice.Created | A trusted-device record is created after a successful authentication interaction. |
79+
| TrustedDevice.Deleted | A user or administrator removes a trusted-device record. |
80+
81+
Natural expiration does not emit a `TrustedDevice.Expired` webhook because expiration is a time-based validity change rather than an application mutation. The `TrustedDevice.Created` payload includes `expiresAt` so consumers can derive the expected expiration time. Successful use and trusted-device policy changes do not emit lifecycle webhooks.
82+
7483
### Management API triggered events \{#management-api-triggered-events}
7584

7685
| API endpoint | Event |

docs/end-user-flows/README.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ End-user flows cover all verification processes for user interactions, categoriz
1616
| ---------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1717
| [Sign-up and sign-in](/end-user-flows/sign-up-and-sign-in) | <ul><li>[Email / phone / username sign-up](/end-user-flows/sign-up-and-sign-in/sign-up)</li><li>[Email / phone / username sign-in](/end-user-flows/sign-up-and-sign-in/sign-in)</li><li>[Social login](/end-user-flows/sign-up-and-sign-in/social-sign-in)</li><li>[Passkey sign-in](/end-user-flows/sign-up-and-sign-in/passkey-sign-in)</li><li>[Reset password](/end-user-flows/sign-up-and-sign-in/reset-password)</li><li>[Terms & Privacy](/end-user-flows/sign-up-and-sign-in/terms-and-privacy)</li><li>[Disable user registration](/end-user-flows/sign-up-and-sign-in/disable-user-registration)</li></ul> |
1818
| [Enterprise SSO](/end-user-flows/enterprise-sso) | <ul><li>[SP-initiated SSO](/end-user-flows/enterprise-sso/sp-initiated-sso)</li><li>[IdP-initiated SSO](/end-user-flows/enterprise-sso/idp-initiated-sso)</li></ul> |
19-
| [Multi-factor authentication](/end-user-flows/mfa) | <ul><li>[Authenticator apps OTP](/end-user-flows/mfa/authenticator-app-otp)</li><li>[Passkeys (WebAuthn)](/end-user-flows/mfa/webauthn)</li><li>[Backup codes](/end-user-flows/mfa/backup-codes)</li></ul> |
19+
| [Multi-factor authentication](/end-user-flows/mfa) | <ul><li>[Authenticator apps OTP](/end-user-flows/mfa/authenticator-app-otp)</li><li>[Passkeys (WebAuthn)](/end-user-flows/mfa/webauthn)</li><li>[Backup codes](/end-user-flows/mfa/backup-codes)</li><li>[Trusted devices](/end-user-flows/mfa/trusted-devices)</li></ul> |
2020
| [Authentication parameters](/end-user-flows/authentication-parameters) | <ul><li>[First screen](/end-user-flows/authentication-parameters/first-screen)</li><li>[Direct sign-in](/end-user-flows/authentication-parameters/direct-sign-in)</li></ul> |
2121
| [Magic link (One-time token)](/end-user-flows/one-time-token) | <ul><li>Organization member invitation</li><li>User invitation when registration is disabled</li><li>Sign in or sign up using magic link</li></ul> |
2222
| Authorize third-party apps | <ul><li>[Consent screen for OIDC / OAuth apps](/end-user-flows/consent-screen)</li></ul> |

docs/end-user-flows/account-settings/by-account-center-ui.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,3 +232,4 @@ If you need more customization beyond what the prebuilt UI and custom CSS offer,
232232
- [Account settings by Account API](/end-user-flows/account-settings/by-account-api) - Build custom account management with full API control
233233
- [Account settings by Management API](/end-user-flows/account-settings/by-management-api) - Admin-level account management
234234
- [MFA configuration](/end-user-flows/mfa) - Set up multi-factor authentication
235+
- [MFA trusted devices](/end-user-flows/mfa/trusted-devices) - Configure and manage time-limited browser trust

docs/end-user-flows/mfa/README.mdx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,7 @@ Logto simplifies the MFA activation process with a one-click toggle, removing th
4242
- [SMS verification](/end-user-flows/mfa/sms-mfa): Use SMS messages to send one-time codes (verification codes) for authentication.
4343
- [Email verification](/end-user-flows/mfa/email-mfa): Use email messages to send one-time codes (verification codes) for authentication.
4444
- [Backup codes](/end-user-flows/mfa/backup-codes): Generate one-time-use backup codes for emergency access.
45+
46+
**Related MFA capabilities**:
47+
48+
- [Trusted devices](/end-user-flows/mfa/trusted-devices): Let users skip repeated MFA prompts on a trusted browser with a time-limited, revocable credential.
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
---
2+
sidebar_position: 7
3+
sidebar_label: Trusted devices
4+
---
5+
6+
# MFA trusted devices
7+
8+
MFA trusted devices let users skip repeated MFA prompts on a browser they trust. After a user completes an eligible MFA challenge and chooses to trust the browser, Logto stores a time-limited credential in a first-party cookie. On a later sign-in, a valid credential can fulfill the MFA verification step without user interaction.
9+
10+
A trusted device is not a new MFA factor and does not change when Logto requires MFA. It can fulfill only the MFA step in a sign-in flow. It cannot satisfy identity verification, recent verification, account recovery, MFA factor management, or another sensitive account operation.
11+
12+
## How trusted devices work \{#how-trusted-devices-work}
13+
14+
When a sign-in reaches the MFA verification step, Logto:
15+
16+
1. Evaluates the existing MFA policy to decide whether MFA is required.
17+
2. Checks whether trusted devices are enabled for the tenant and allowed by every organization the user belongs to.
18+
3. Validates the browser cookie against an active server-side record for the identified user.
19+
4. Completes MFA automatically when the credential is valid. Otherwise, Logto clears an invalid credential and continues with the conventional MFA flow.
20+
21+
After a successful conventional MFA challenge, the built-in sign-in experience can show an unchecked option to trust the browser for the configured duration. Logto creates the trusted-device record only after the complete interaction succeeds. Trusted-device creation and post-sign-in metadata updates are best effort, so a failure does not fail an otherwise successful sign-in.
22+
23+
Users can create trust after successfully verifying with an authenticator app OTP, passkey (WebAuthn), email verification code, or SMS verification code. Successfully binding an authenticator app or passkey during an MFA setup flow is also eligible. Backup code verification and a sign-in already fulfilled by another trusted device cannot create a new trusted device.
24+
25+
## Configure the trusted-device policy \{#configure-the-trusted-device-policy}
26+
27+
### Global policy \{#global-policy}
28+
29+
Navigate to <CloudLink to="/mfa">Console > Multi-factor authentication</CloudLink> and configure **Trusted devices**:
30+
31+
- Enable or disable trusted devices for the tenant. The policy is disabled by default.
32+
- Set a whole-number trust duration from 1 through 365 days. The default is 30 days.
33+
34+
The duration is fixed when a trusted device is created. Using the device does not extend its expiration time, and changing the duration affects only devices created afterward.
35+
36+
Disabling the global policy prevents existing trusted devices from fulfilling MFA, but does not delete them. If you enable the policy again, records that have not expired or been removed can become usable again.
37+
38+
### Organization-level restrictions \{#organization-level-restrictions}
39+
40+
An organization can allow or disallow trusted devices for its members. This setting can only tighten the tenant-level policy:
41+
42+
- An organization cannot enable trusted devices when the global policy is disabled.
43+
- If any organization the user belongs to disallows trusted devices, the user's trusted-device credential cannot fulfill MFA, regardless of whether that organization requires MFA.
44+
- Organizations do not have a separate trust duration. The global duration applies.
45+
46+
Disallowing trusted devices for an organization suspends their use for affected members. It does not delete their records, and it does not prevent users or administrators from listing or removing them.
47+
48+
## Browser and cookie limitations \{#browser-and-cookie-limitations}
49+
50+
Trusted-device reuse requires the browser context to preserve and return a persistent first-party cookie for the same Logto endpoint. It represents a browser profile, not a physical device.
51+
52+
WebViews, system browsers, custom tabs, privacy modes, cookie-disabled browsers, and other ephemeral contexts can use trusted devices only when their cookie store persists the credential. If the cookie is unavailable on a later sign-in, Logto continues with conventional MFA instead of failing authentication. Different browsers, browser profiles, Logto domains, tenants, and users do not share trusted-device credentials.
53+
54+
:::note
55+
Logto does not use browser fingerprinting or pre-detect whether a client will persist the cookie. Native apps and custom sign-in flows should treat trusted-device creation as best effort and keep the conventional MFA flow available.
56+
:::
57+
58+
## Manage trusted devices \{#manage-trusted-devices}
59+
60+
Only active records whose `expiresAt` is in the future are listed. Device names are derived from the latest user agent, while country and city are approximate metadata from the latest available request context. Raw IP addresses are not displayed or returned by the public APIs.
61+
62+
### Administrator management \{#administrator-management}
63+
64+
In <CloudLink to="/user">Console > User management</CloudLink>, open a user to view and remove their trusted devices. Removing a trusted device affects future sign-ins only; it does not terminate the user's active sessions.
65+
66+
You can also use the Management API:
67+
68+
- `GET /api/users/{userId}/trusted-devices` lists all active trusted devices for a user.
69+
- `DELETE /api/users/{userId}/trusted-devices/{trustedDeviceId}` removes one trusted device owned by the user.
70+
71+
The list response includes `id`, `userAgent`, `country`, `city`, `createdAt`, `lastUsedAt`, and `expiresAt`.
72+
73+
```bash
74+
curl https://[tenant-id].logto.app/api/users/[user-id]/trusted-devices \
75+
-H "Authorization: Bearer [management-api-access-token]"
76+
77+
curl -X DELETE \
78+
https://[tenant-id].logto.app/api/users/[user-id]/trusted-devices/[trusted-device-id] \
79+
-H "Authorization: Bearer [management-api-access-token]"
80+
```
81+
82+
Learn how to [authenticate with the Management API](/integrate-logto/interact-with-management-api).
83+
84+
### Account Center self-service management \{#account-center-self-service-management}
85+
86+
In <CloudLink to="/sign-in-experience/account-center">Console > Sign-in & account > Account center</CloudLink>, configure the **Trusted devices** field:
87+
88+
- **Off**: users cannot list or remove trusted devices.
89+
- **Read-only**: users can list trusted devices but cannot remove them.
90+
- **Edit**: users can list and remove trusted devices.
91+
92+
The prebuilt Account Center displays active trusted devices on its security page and marks the current browser when its complete cookie credential is valid. Removing the current browser clears its trusted-device cookie but keeps the current login session active. Removing another browser's record cannot clear that browser's cookie immediately; the stale cookie is rejected and cleared when it is next presented.
93+
94+
For a custom account center, request the `urn:logto:scope:trusted_devices` scope and use the Account API with a valid identity verification record:
95+
96+
- `GET /api/my-account/trusted-devices` lists the signed-in user's active trusted devices and adds `isCurrent` to each item.
97+
- `DELETE /api/my-account/trusted-devices/{trustedDeviceId}` removes one trusted device owned by the signed-in user. Deletion is available only to first-party applications.
98+
99+
```bash
100+
curl https://[tenant-id].logto.app/api/my-account/trusted-devices \
101+
-H "Authorization: Bearer [account-api-access-token]" \
102+
-H "logto-verification-id: [verification-record-id]"
103+
104+
curl -X DELETE \
105+
https://[tenant-id].logto.app/api/my-account/trusted-devices/[trusted-device-id] \
106+
-H "Authorization: Bearer [account-api-access-token]" \
107+
-H "logto-verification-id: [verification-record-id]"
108+
```
109+
110+
See the [Account API reference](https://openapi.logto.io/group/endpoint-account-center) and [security verification guide](/end-user-flows/security-verification) for the authorization and verification flow.
111+
112+
## Security model \{#security-model}
113+
114+
The trusted-device credential is an opaque bearer credential with two parts: a record ID and a cryptographically random 32-byte secret.
115+
116+
- In production, Logto stores it in a host-only cookie with the `__Host-` prefix, `HttpOnly`, `Secure`, `SameSite=Lax`, and `Path=/` attributes. Application JavaScript cannot read it.
117+
- The server stores only the SHA-256 hash of the secret and compares credentials with a timing-safe check.
118+
- Every credential lookup is constrained to the tenant and user and requires `expiresAt` to be in the future.
119+
- Expiration is fixed at creation. Opportunistic cleanup can delete expired rows later, but cleanup timing is never used as a security control.
120+
- Explicit removal deletes the server-side record immediately. A copied or stale cookie cannot pass validation after the record is removed.
121+
122+
Credential secrets and hashes are never exposed through UI, public APIs, audit logs, or webhooks. The public device ID is not a physical-device identifier and is not sufficient to authenticate. Because the cookie is a bearer credential, copying the complete cookie can replay trust for the same tenant and user until the record expires or is removed; trusted devices do not provide hardware-backed device attestation.
123+
124+
## Audit logs and webhooks \{#audit-logs-and-webhooks}
125+
126+
Trusted-device-specific audit logs include:
127+
128+
- `TrustedDevice.Created`: a trusted-device record and cookie credential were created after a successful interaction.
129+
- `TrustedDevice.Used`: a trusted-device credential fulfilled MFA and the sign-in completed successfully.
130+
131+
You can subscribe to these data mutation webhooks:
132+
133+
- `TrustedDevice.Created`: a trusted-device record was created.
134+
- `TrustedDevice.Deleted`: a user or administrator removed a trusted-device record.
135+
136+
The event data contains the trusted-device `id`, `userId`, and `expiresAt`. It excludes the cookie credential, secret hash, and request IP. There is no webhook for successful use to avoid high event volume, and policy changes do not emit trusted-device lifecycle events because they do not mutate records.
137+
138+
Natural expiration has no `TrustedDevice.Expired` webhook. Expiration occurs when time passes rather than when an application mutation runs, and physical cleanup may happen later. Use the `expiresAt` value from `TrustedDevice.Created` if your integration needs to derive the expected expiration time.
139+
140+
Natural expiration also does not create a trusted-device-specific audit log.
141+
142+
See [audit log event types](/developers/audit-logs/event-types#mfa) and [webhook events](/developers/webhooks/webhooks-events) for the event catalogs.
143+
144+
## Lifecycle notes \{#lifecycle-notes}
145+
146+
- Normal sign-out does not remove trusted devices.
147+
- Adding, removing, or resetting MFA factors does not remove trusted devices.
148+
- Removing a trusted device does not terminate active sessions.
149+
- Deleting the user deletes their trusted-device records through the user data lifecycle.
150+
- There is no trusted-device count limit or automatic eviction.

0 commit comments

Comments
 (0)