Sign-in Experience now supports es-MX (Spanish, Mexico).
For users whose language is Spanish (Mexico), phone inputs default to the Mexico country code (+52). This release also fixes list formatter placeholders and the remaining untranslated MFA message in the Spanish locales.
Security hardening
SSRF protection for webhooks and enterprise SSO
Outbound requests configured through the Management API are now blocked when they resolve to loopback, private, link-local, cloud metadata, or other special-use addresses.
Protection now covers:
- Webhook delivery, including
POST /api/hooks/:id/test. - OIDC enterprise SSO discovery, token, and userinfo requests.
- SAML identity-provider metadata fetching.
- Every redirect hop made by these requests.
DNS names are checked when the connection is established, so a hostname that resolves to a protected address is rejected like a literal IP address.
Token exchange validation
In addition to requiring first-party subject tokens, Logto now validates that a JWT presented as an access_token subject is actually an access token.
The JWT must contain:
- The RFC 9068
at+jwttype header. - A
client_idclaim.
OIDC ID tokens and other JWTs signed by the tenant can no longer be substituted for an access token. Invalid subject tokens are rejected with invalid_grant.
Third-party Account API restrictions
Third-party applications can no longer mutate account data through the Account API or Verification API. Such requests now return:
403 auth.third_party_application_forbidden
First-party applications, including Account Center and Console, are unaffected.
The check fails closed for unresolved client identifiers. This includes deleted applications whose access tokens are still active and CIMD clients whose identifier is a metadata URL.
No read route received a new direct guard. However, the following reads require verification records created through guarded routes and are therefore no longer reachable by third-party applications:
GET /api/my-account/grantsGET /api/my-account/sessionsGET /api/my-account/mfa-verifications/backup-codes
Suspended users cannot receive new tokens
Token issuance and userinfo now reject suspended users with invalid_grant, matching the existing behavior for deleted users.
This applies across refresh token, authorization code, device code, and token exchange flows, even if an earlier token or session revocation did not complete successfully.
Third-party application scopes are revalidated
Removing a user scope from a third-party application's consent configuration now affects existing grants as well as new authorization requests.
- Refresh token exchanges drop scopes that are no longer configured.
- Authorization requests resuming an existing grant fail with
invalid_scopewhen appropriate. - Organization token requests fail with
insufficient_scopeafter the organizations scope is removed. - Consent submission no longer grants a scope that was removed while the consent screen was open.
Identifier lockouts use normalized identifiers
Sentinel lockout counters now use the same normalized identifier form as account lookup:
- Email addresses are lower-cased.
- Phone numbers are canonicalized.
- Usernames are case-folded only when the tenant's username policy is case-insensitive.
This prevents alternate spellings of the same identifier from creating separate attempt buckets and weakening maxAttempts.
Manual unlock also clears equivalent spellings where they identify the same account. After upgrading, an existing lockout recorded under a non-canonical spelling may end early, but no user becomes more locked out than before.
Redirect validation
- Social landing-page
redirect_tovalues must usehttporhttps. - Native callback links must use a custom application scheme.
- Stored callback links are checked again before the browser returns control to a native app.
- The unused Experience Springboard route has been removed to eliminate an untrusted redirect surface.
Bug fixes & stability
Authentication and authorization
- Revoking a user's third-party application authorization now invalidates only that application's tokens. The user's browser SSO session remains active.
- Elliptic Curve signing keys now advertise the algorithm matching their curve: P-256 uses
ES256, P-384 usesES384, and P-521 usesES512. - Switching from passkey sign-in to verification-code sign-in no longer prevents users from completing CAPTCHA.
- OIDC
invalid_scopeandinsufficient_scopemessages now show the rejected scope instead of raw{{error_description}}or{{scope}}placeholders.
Experience and localization
- Safari and other password managers can now suggest and save a strong password on set-password and reset-password screens using the correct account identifier.
Accept-Languagequality values with whitespace, such asen; q=0.7, are now parsed correctly. Invalid quality values fall back safely instead of producingNaN.- Gmail custom allowlist and blocklist matching now treats
gmail.comandgooglemail.comas equivalent and ignores dots in the local part. - Console now provides clearer examples, descriptions, and shorter placeholders for custom email rules.
Account Center and Management API
- Saving Account Center or sign-up settings now drops references to deleted custom profile fields instead of returning
custom_profile_fields.entity_not_exists_with_names. - Deleted fields remain removable from Console even when their permission control is Off.
- Management API relation endpoints now accept empty scope or role arrays as no-ops instead of returning a 500 error. This includes endpoints such as:
POST /applications/:applicationId/user-consent-scopesPOST /organizations/:id/users/:userId/roles
- Date validation now matches the complete input and rejects trailing characters after an otherwise valid date.
Webhook delivery
Webhook POST requests now retry up to three times when the endpoint returns an HTTP 5xx response, matching the documented delivery contract.
Because a retried event may be delivered more than once, webhook receivers should process events idempotently.
Connectors
Microsoft Azure AD
The Microsoft Azure AD connector now supports a disableEmailSync option.
By default, the connector continues to copy the Microsoft Graph mail attribute into the Logto user profile. Enable this option when the connector should authenticate the user without synchronizing that address, matching the existing control available for Azure OIDC enterprise SSO.
Self-hosting & OSS notes
-
Action required — outbound request protection: If webhooks or enterprise SSO connectors intentionally access services on a private network, add the required IP addresses or CIDR ranges to
SSRF_ALLOWED_ADDRESSESbefore upgrading:SSRF_ALLOWED_ADDRESSES=10.0.0.0/8,127.0.0.1Allowlisting only the required destinations is safer than disabling protection globally.
-
Dynamic app compatibility: Configuring
SSRF_ALLOWED_ADDRESSESdisables CIMD so unauthenticated dynamic clients cannot use the allowlist to reach private services. SettingSSRF_PROTECTION_DISABLED=truealso disables CIMD. -
Configuration compatibility:
OIDC_PROVIDER_SSRF_PROTECTION_DISABLEDremains supported as an alias forSSRF_PROTECTION_DISABLED. These variables apply only to self-hosted deployments. -
Script runtime limits: Custom JWT and Actions scripts must complete within 5 seconds, stay within the 128 MB worker memory budget, and return JSON-serializable values.
-
Database migration required: This release ships new schema alterations and indexes. After upgrading, run the database alteration command (
npm run alteration deployin the@logto/cli/core image, orlogto db alteration deploy) before starting the new version. See the upgrade guide.
Contributors
Huge thanks to the community members whose work shipped in this release:
- @arpitjain099 - complete-string date validation (#9266)
- @shuvamk - RFC-compliant
Accept-Languagequality parsing (#9338) - @darcyYe - webhook retries for HTTP 5xx responses (#9410)
For the complete list of changes, see the full changelog.