Changelog
Every change that an integration can observe — new endpoints and scopes, changed responses, and corrected behaviour — with the date it landed and the environments that have it.
dev first and a given environment only at its next deployment. An entry marked Development is not yet present on the production base URL. See Environments & base URLs for what each one currently serves.2026-10-27 — Independent email delivery tracking
Email delivery status stays available when optional tenant sender settings are incomplete.
Fixed
| Change | What it means for you | Availability |
|---|---|---|
| Platform delivery tracking is independent of tenant sender readiness | SES delivery events continue to be processed when optional tenant sender configuration is unavailable. Queue preflight and authentication-host DNS requirements remain enforced; no new environment keys are required. | Development |
2026-10-26 — Consistent sign-in proof, session and device-trust rules
Development changes for the coordinated 6.2–6.4 batch release.
Changed
| Change | What it means for you | Availability |
|---|---|---|
| Invalid reverify sessions have one terminal response | Reverify now returns 401 session_invalid for unknown, expired or revoked sessions. Clear local confirmation state and require sign-in; 409 flow_superseded remains for stale flows. | Development |
Fixed
| Change | What it means for you | Availability |
|---|---|---|
| Setup respects the account-wide strongest factor | A passkey on another RP also sets the setup proof floor. Handle stronger_proof_unavailable_here with recovery-code or original-site security guidance. | Development |
| Hosted trust uses the same current server decision as API sign-in | Offer trust only when the server permits it. Hosted and direct proofs report remember_device_unavailable when that choice is unavailable. Authenticator replacement sends a dedicated security notice. | Development |
2026-10-25 — Self-service factors and v2-only API sign-in
Backend-owned sign-in can manage the user's own strong factors with shared fresh-proof rules.
Added
| Change | What it means for you | Availability |
|---|---|---|
| App-bound factor management and one-time recovery codes | See self-service 2FA. First strong-factor binding returns recovery codes once in API, flow and hosted responses. Hosted TOTP confirm now returns HTTP 200 JSON. | Development |
Changed
| Change | What it means for you | Availability |
|---|---|---|
| Removed legacy email login, old session reverify and legacy invite mutation | Use the v2 login flow and app-bound reverify. Removed endpoints return 410 endpoint_removed; preflight defaults to v2. The legacy protection switch is removed. | Development |
Fixed
| Change | What it means for you | Availability |
|---|---|---|
| Typed app mismatch and actionable trusted-device fields | Other-app sessions return 403 session_app_mismatch. Verification steps expose effective remember-device availability and duration. Hosted passkey rename now requires fresh proof. | Development |
2026-10-22 — OAuth interoperability and legacy sign-in protection
Available in development; production rollout requires operator configuration and migration review.
Added
| Change | What it means for you | Availability |
|---|---|---|
| Public tenant IDs in signed installation payloads | New enrolment receipts and installation revocation events add tenant_public_id beside the UUID tenant_id. Existing UUID validation stays unchanged; older payloads may omit the new field. | Development |
Changed
| Change | What it means for you | Availability |
|---|---|---|
| Policy protection and migration signals for legacy email-code login | New tenants require the flow API for users with an enrolled authenticator or passkey. Existing tenants retain their setting until an operator enables protection. See the migration guide for the password-bound conflict and lifecycle headers. | Development |
Fixed
| Change | What it means for you | Availability |
|---|---|---|
| Standard Basic client authentication on the token endpoint | Client credentials now accept HTTP Basic as advertised by discovery. Client IDs and secrets use OAuth form encoding inside Basic; mixed credentials and inconsistent client IDs are rejected with a Basic challenge. | Development |
2026-10-21 — Generally available in production
Production now runs everything on this page. Every earlier entry is available on the production base URL, and passkeys, authenticator apps, recovery codes and sign-in strength are generally available.
Added
| Change | What it means for you | Availability |
|---|---|---|
| Passkeys, authenticator apps and recovery codes for end users | Users can sign in with a WebAuthn passkey, an authenticator app (TOTP), an emailed one-time code or a single-use recovery code, on hosted login and through the API. Each organisation chooses which methods are allowed and can stage a requirement for a stronger method; a method the resolved policy disables is refused with a stable error code (see Errors). | All environments |
| Requested sign-in strength and step-up | Tokens report how the user signed in in amr and acr. Request a minimum with acr_values on hosted login or min_acr on the API (urn:authreads:acr:mfa, urn:authreads:acr:phr), and a fresh proof with max_age; handle unmet_authentication_requirements when no method qualifies. Essential acr requests through the claims parameter remain unsupported and are rejected. See Requesting sign-in strength and Step-up re-verification. | All environments |
Changed
| Change | What it means for you | Availability |
|---|---|---|
| Earlier entries are now in production | Entries previously marked Development shipped with this deployment and are now marked All environments. Review relying-party claim allow-lists for the pop and mfa amr values introduced on 2026-10-09. | All environments |
2026-10-09 — Hosted passkey sign-in and verified authentication claims
Organisation-enabled passkeys can complete hosted sign-in on the exact login site where they were added.
Changed
| Change | What it means for you | Availability |
|---|---|---|
| User-verified passkeys include pop and mfa | Newly issued tokens report pop and mfa for a cryptographically user-verified passkey. Password plus passkey also includes pwd. Existing tokens keep their claims. Review relying-party claim allow-lists before deployment. This does not assert hardware binding or change operator enforcement. | All environments |
2026-09-28 — Management rename requests reject unsupported fields
Role and package rename requests now report an invalid request when a caller supplies fields the operation cannot change.
Changed
| Change | What it means for you | Availability |
|---|---|---|
| Unknown fields in role and package PATCH bodies receive 422 | PATCH /api/v1/management/roles/{role_id} and PATCH /api/v1/management/packages/{package_id} accept only name. An unsupported key or any other unknown field now returns 422 instead of silently applying the rename. Body errors on these two routes are now application/problem+json with a code (invalid_request_body, malformed_json, unsupported_media_type, request_body_unreadable) instead of plain text. | All environments |
Fixed
| Change | What it means for you | Availability |
|---|---|---|
| Step-up retains a session's original authentication method | Newly minted token amr now includes the distinct methods verified when a session was created and at its latest step-up. auth_time continues to reflect the latest successful proof. No new authentication method is emitted by this change. | All environments |
2026-09-25 — Machine ownership and per-person admission
Tenant automation can assign a machine owner and enforce an audited active-machine limit per person.
Added
| Change | What it means for you | Availability |
|---|---|---|
| Machine ownership and tenant-managed person limits | Machine ownership can be assigned, transferred, cleared, or marked shared. The tenant default and per-person exceptions are managed with installations:manage. A verified binding claim that exceeds the limit now returns 409 person_installation_limit_reached with the limit, current count, and the person's active machine IDs; the binding is not consumed. Deleting a user who still owns active machines returns 409 user_owns_active_installations; release or transfer their machines before retrying. | All environments |
2026-09-16 — Verifiable enrolment and machine revocation delivery
Machine enrolment now produces proof a customer's backend can verify, and a configured customer endpoint can receive durable signed revocation events.
Added
| Change | What it means for you | Availability |
|---|---|---|
| Enrolment redemption returns a signed, key-bound receipt | POST /api/v1/enrolment/redeem now adds an enrolment_receipt JWT to its existing response. The receipt is valid for five minutes, is audience-bound to the enrolled app, and binds the installation, tenant, app, and SHA-256 fingerprint of the canonical enrolled public key. Verify it with the issuer's published JWKS before your backend accepts the agent's key. This is additive; no existing response field changed. | All environments |
| Signed installation-revocation notifications | An app may register one public HTTPS revocation destination. Retiring an installation then enqueues a signed secevent+jwt notification containing a unique jti, tenant, app, installation, and reason class. Delivery is retried and may be duplicated, so receivers must be idempotent. It remains best-effort: absence of an event is never proof that an installation is active. See the installation protocol for the receiver contract. | All environments |
Fixed
| Change | What it means for you | Availability |
|---|---|---|
| A stale out-of-range policy field no longer hides the entire policy | A previously saved numeric policy value that is outside today's permitted range now resolves to the current platform default for that field only. The response reports the substitution in degraded_fields, and saving the policy repairs the stale override. Malformed policy data still fails visibly, and new writes remain range-validated. | All environments |
2026-09-15 — Complete machine lifecycle automation
Tenant backends can now issue bounded machine tickets and retire individual installations through the public Management API.
Added
| Change | What it means for you | Availability |
|---|---|---|
| Issue one-use machine enrolment tickets | POST /api/v1/management/apps/{app_id}/machine-enrolment-tickets lets a tenant backend mint a one-hour, single-use ticket with the new enrolment:issuescope. The caller can provide only purpose and deployment campaign; lifetime and use count cannot be widened. | All environments |
| Retire one machine installation | PUT /api/v1/management/apps/{app_id}/installations/{installation_id}/revocation adds least-privilege machine retirement with installations:revoke. It is idempotent, releases capacity, requires an audit reason, and deliberately operates on one installation rather than an entire deployment campaign. Already-issued access tokens may remain valid for up to 15 minutes. | All environments |
2026-09-07 — Consent-bound attribution is reachable
People can bind external identities, manage disclosure consent, and request erasure through the published account API and hosted surfaces.
Added
| Change | What it means for you | Availability |
|---|---|---|
| Attribution binding, consent, withdrawal, and erasure API | OIDC clients operating their own account UI may request account:attributionand call the /oauth/account/... binding, consent, withdrawal, and erasure endpoints. Hosted account pages authenticate their own session and do not require this scope. Attribution tokens remain audience-bound and consent-bound; see the OIDC and installation protocol documentation. | All environments |
2026-08-12 — Bounded fleet enrolment and Phase 4 write errors
Fleet enrolment now rejects database conflicts with stable codes, preserves retry accounting, and applies pre-database abuse controls plus operator-bounded tenant capacity.
Changed
| Change | What it means for you | Availability |
|---|---|---|
| Anonymous redemption and installation capacity are genuinely bounded | /api/v1/enrolment/redeem now passes a two-bucket limiter before opening a database transaction. Tenant limit changes cannot exceed their operator-approved maximum; platform exceptions use a separate permission boundary and durable audit event. | All environments |
Fixed
| Change | What it means for you | Availability |
|---|---|---|
| Phase 4 constraint failures now have actionable codes | Duplicate installation keys, concurrent external-principal claims, duplicate issuers, and invalid tenant-scoped app/workspace/identity references no longer collapse into an internal error. Values are additive and permanent; integrations should retain a default branch for future codes. | All environments |
2026-08-12 — Machine-readable login failures and consistent native logout
Direct and hosted login now share stable actionable codes, and native apps can use the same loopback redirect policy when signing out as when signing in.
Added
| Change | What it means for you | Availability |
|---|---|---|
| Local back-channel logout development guidance | Use a temporary public HTTPS tunnel to a local receiver. Local, private, non-HTTPS, and redirecting targets stay refused in every environment so production SSRF protection and development behavior cannot diverge. | All environments |
Changed
| Change | What it means for you | Availability |
|---|---|---|
| Credential and rate-limit responses now emit stable codes | Direct problem responses now emit invalid_credentials for rejected login proofs and rate_limited for general limits. Hosted OAuth responses emit the same values in error_code; login_temporarily_locked remains unchanged. These fields are additive where no code was emitted before. Integrations with adefault: branch should add explicit cases if they want tailored user messages or retry behavior. Wrong passwords and unknown identities remain byte-identical. | All environments |
Fixed
| Change | What it means for you | Availability |
|---|---|---|
| Post-logout loopback redirects match authorization redirects | Native clients may register HTTP post-logout redirects on localhost, 127.0.0.1, or [::1], and may use a different runtime port. Scheme, host, path, and query still match; every non-loopback target remains exact HTTPS. | All environments |
| Trusted-device alerts are branded and now name the device, time, and a way to act | The trusted-device notification your users receive previously arrived unbranded and told them to remove the device without saying where. It now carries the standard Authreads layout and states the device, platform, IP address and time, with a link to the hosted account-security page. The link is built from your configured hosted-login origin, so it points at the page your users already use. Every Authreads email now also sends a plain-text alternative alongside the HTML part, which improves deliverability for one-time-code mail. A tenant administrator can still disable the trusted-device alert under Authentication → Security policy; doing so does not suppress the trusted_device.created audit record or the device inventory entry. | All environments |
| Set-password emails name the right sender, reason, and expiry | One template served two unrelated situations, so a user who requested a first password through forgot-password was told “You have been invited” and warned to be suspicious of a message they had just asked for. These are now separate emails. The self-service one states that the reader asked for it; the invitation one is subject-lined <your company name> invited you — set your password and names your company in the body, because your users were invited to your application and do not recognize Authreads.Invitation and onboarding emails also stated the wrong lifetime: they promised one hour for links that are valid for seven days, so recipients abandoned working links and asked for re-sends they did not need. Every link email now states the lifetime its token is actually minted with. No token lifetime changed — only the wording, which was wrong. | All environments |
2026-08-11 — Reliable OIDC session termination
Relying parties can now receive a signed, durable notification when an Authreads OIDC session is revoked or reaches its absolute expiry.
Added
| Change | What it means for you | Availability |
|---|---|---|
| OpenID Connect Back-Channel Logout 1.0 | Register an HTTPS backchannel_logout_uri on your OIDC client and implement the standard logout_token receiver. Authreads retries temporary delivery failures without delaying the user's logout, and the client settings show repeated failures. Verify the token signature, issuer, audience, lifetime and logout event; reject a token containing nonce; deduplicate on jti; then end the session identified by sid. See Sign in with Authreads. | All environments |
Changed
| Change | What it means for you | Availability |
|---|---|---|
| Hosted lockouts include a stable extension code | Hosted OAuth lockouts still use the standards-compatible temporarily_unavailableerror, and now also include error_code: login_temporarily_locked. Branch on that extension instead of matching human-readable prose. | All environments |
Fixed
| Change | What it means for you | Availability |
|---|---|---|
| Idle-timeout scope is documented explicitly | Authreads enforces idle timeout on hosted browser sessions and direct/BFF integrations that present x-session-activity. A hosted OIDC relying party must enforce human inactivity in its own session; read idle_timeout_minutes from the signed https://authreads.com/claims/session_policy ID-token claim. Back-channel logout carries Authreads revocation and absolute-expiry decisions, but does not turn a server-side token operation into proof of user activity. | All environments |
2026-08-11 — Live policy inheritance and honest login errors
A tenant's security policy now actually inherits platform-default changes, and a locked-out login is no longer indistinguishable from an expired OAuth grant.
Fixed
| Change | What it means for you | Availability |
|---|---|---|
| Tenant security policy inherits platform-default changes again | A tenant's policy row previously stored a full copy of every platform default, not only the fields it deliberately chose, so a platform-default change never reached any tenant — password, MFA, lockout, and trusted-device enforcement were evaluated and then silently discarded. Policy rows are now sparse: only deliberate overrides are stored, and every other field resolves against the live platform default on each request. Deliberate tenant customizations are unaffected. See Authentication settings. | All environments |
| Login failures return honest, distinguishable errors | Hosted login failures previously collapsed almost everything into OAuth's generic invalid_grant / "grant invalid, expired, or already used". A temporary lockout is now its own explicit response on both planes, with Retry-After. If you pattern-matched on the old generic grant-error text to detect a lockout, that match will stop firing — branch on code (direct) or the documented OAuth error instead. See Errors & rate limits. | All environments |
| New-trusted-device notification email now actually sends | The notification introduced below never delivered in any environment where the database role is not a superuser — dev or production — because the throttle record backing it was written on the admin connection, which the row's own tenant-isolation policy silently rejects. It now writes on the correct tenant-scoped connection. If you depend on this email, re-verify delivery; nothing about the API contract changed. | All environments |
2026-08-11 — Account security for tenant backends
Self-service session and trusted-device management became reachable from a tenant's own backend, not only from our hosted login pages.
Added
| Change | What it means for you | Availability |
|---|---|---|
| Seven account-security endpoints on the tenant BFF surface | Under /api/v1/auth/users/{user_id}/apps/{app_id}/account-security/: list and revoke sessions, list and revoke trusted devices, a combined revoke-others-and-devices, and a policy read. Previously these existed only behind the hosted OIDC token shape, which a backend-for-frontend integration cannot mint. See Sessions & tokens. | All environments |
| account-security:read and account-security:manage scopes | Both are opt-in and granted to no existing credential automatically. account-security:manage can end another person's access, so it is marked dangerous when granting. See API & credentials. | All environments |
| Per-tenant control of the new trusted-device email | A tenant that would rather send its own branded notification can turn ours off. Delivery is enabled by default. Disabling delivery never suppresses the audit record — the security evidence is written in the same transaction that creates the device. | All environments |
| Trusted devices on the hosted login | The one-time-code step accepts remember_device, and the response returns the window your tenant actually resolved to — so your UI states the real number of days rather than mirroring a constant. Tenants choose any value up to a 90-day platform ceiling. | All environments |
| Session idle timeout | Authreads-hosted browser sessions now end after a period of real pointer or keyboard inactivity as well as at their absolute expiry. Direct/BFF clients enforce the same boundary with the signed activity contract — GET /api/v1/auth/me now requires the current x-session-activity token on every call and fails 401 without it; hosted OIDC relying parties enforce the resolved setting in their own browser session. Tenant-configurable from 15 minutes to 365 days; the platform default is 30 minutes. See Sessions & tokens. | All environments |
Changed
| Change | What it means for you | Availability |
|---|---|---|
| Session exchange returns session policy and activity state | POST /api/v1/auth/session/exchange now also returns session_policy (including the resolved idle timeout) and session_activity_token. The exchange response itself is additive — existing fields are unchanged — but a Direct/BFF client that discards session_activity_token will find its GET /me calls start failing once this reaches its environment, because that endpoint now requires it. | All environments |
| RP-initiated logout no longer requires id_token_hint | GET /oauth/logout now accepts client_id as an alternative, matching OpenID Connect RP-Initiated Logout 1.0, which marks id_token_hint RECOMMENDED rather than REQUIRED. At least one of the two is still required, because the client identity is what validates your post_logout_redirect_uri. Relying parties that discard the ID token after login can now end the session properly instead of receiving a 400. | All environments |
Fixed
| Change | What it means for you | Availability |
|---|---|---|
| Logout could leave the single-sign-on cookie alive | The session cookie was cleared with attributes that did not always match how it was written, so in some deployments the browser kept it and the next sign-in skipped authentication entirely. The deletion now mirrors the write in every configuration. | All environments |
What is not listed here
Internal refactoring, test coverage, administrative console work and documentation edits are deliberately left out, however large. This page exists so you can tell at a glance whether something you integrate against has moved — a list of everything would defeat that.
If a change you depend on is missing, it is an omission rather than a policy. Tell us and we will add it.