Repository navigation
chore: update version and changelog - #495
Open
github-actions[bot] wants to merge 1 commit into
Open
github-actions[bot] wants to merge 1 commit into
github-actions[bot] wants to merge 1 commit into
Conversation
github-actions
Bot
force-pushed
the
changeset-release/main
branch
13 times, most recently
from
October 25, 2026 00:52
3ec9eaa to
586c8df
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
October 25, 2026 01:48
586c8df to
02ca0a7
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and publish to npm yourself or setup this action to publish automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.
Releases
seamless-auth-api@0.20.0
Minor Changes
baa7dbc: Self-service account recovery through a verified email or phone, with a delay and notices (feat: self-service account recovery with a delay and notifications #399).
POST /recovery/startsends a six-digit code to the verified address on the chosen channel, answering the same whether or not the account has one.POST /recovery/verifyopens the request, which completes only afteraccount_recovery.delay, and tells the account's verified email and phone how to cancel it.GET /recovery/statusreportspending,ready,cancelledorcompleted.POST /recovery/canceltakes the token from the notice's link and needs no session.POST /recovery/completeon a ready request signs out every session and issues a restricted recovery session.ACCOUNT_RECOVERY). Not blocked by account lockout; five wrong codes void a request.GET /system-config/publicreportsaccountRecovery.account_recovery_requeststable.See docs/account-recovery.md.
Self-service recovery is unavailable in
phishing_resistant_onlymode, since it proves only an address;GET /system-config/publicreportsaccountRecovery: falsethere. Cancelling an open request always works.c9f4a6c: Admin writes require a fresh step-up on the calling session (feat(admin): require step-up for config, role and user deletion writes #437).
System config and OAuth provider writes, user create, import, update and delete, admin session revocation, organization admin writes and provider retirement, and
POST /organizations/{organizationId}/membersnow runrequireStepUp()after the admin role check, as device replacement and the audit export already did. Without a WebAuthn or TOTP step-up in the last five minutes they answer403witherror: "step_up_required"and the session's step-up status. Each route documents that403inopenapi.json. Admin reads and enrollment invites are unchanged.Breaking for scripts and clients that call these routes with a plain admin access token: step up first (
POST /totp/verify-mfaor/step-up/webauthn/*on the same session), then retry. The admin console already steps up before these writes, except organization create and update, which need a console update to prompt first. The CLI's admin write commands fail with a permission error until it learns to step up.DELETE /users/delete(a user deleting their own account) needs a fresh step-up too. An account with no passkey or TOTP cannot step up, so it can only be deleted by an administrator.4256967: Break-glass admin accounts that no sign-in policy can lock out (feat: break-glass admin that no policy can disable #401).
BREAK_GLASS_EMAILS(comma separated, matched case-insensitively). A listed account that holds a role satisfyingadmin:writeis exempt fromlogin_methods,phishing_resistant_only,passkey_login_fallback_enabledandrecovery_codes.enabledfor its own sign-in, and fromauthenticator_policywhen it enrolls a passkey. A listed address without the role gets no exemption, and boot logs how many listed entries are not admin accounts.403 login_method_disabled) even where they are enabled for everyone else, and session issuance refuses them as a backstop. Lockout still applies to its TOTP./loginadds a break-glass account's passkey whenlogin_methodsleaves passkeys out, and lets one holding only TOTP or recovery codes continue where it would otherwise be answered as a decoy. ItsloginMethodsis otherwise shaped like any account's, so it can list methods the account is then refused.break_glass_sign_inauth event withseverity: "high"in its metadata and emails a notice to every admin account with a verified email.See the Break-glass admin section of docs/admin-operations.md.
A passkey a break-glass admin enrolls outside the authenticator policy is announced like a waived sign-in: a
break_glass_enrollmentevent withseverity: 'high'and a notice to every admin.7ae63d1: Recovery codes, and restricted recovery sessions (feat: recovery codes #398).
GET /recovery-codesreports how many of the user's codes are left.POST /recovery-codesreturns a new set of ten single-use codes (XXXXX-XXXXX), the only time they are shown, and invalidates the previous set; replacing a set needs a fresh step-up. Codes are stored as keyed hashes.POST /recovery-codes/redeem, with the pre-auth token from/login, signs in with a code. It is rate limited like an OTP, is not subject to account lockout, and works whateverlogin_methodsorphishing_resistant_onlysay. Turned off withrecovery_codes.enabled.recovery: trueandnextStep: "enroll_passkey"in the response, arecovery: trueclaim in the access token, and403 enrollment_requiredon every access route except passkey and TOTP enrollment, recovery codes,GET /users/meand logout, until a new factor is enrolled. Refreshing keeps the restriction; enrolling lifts it.POST /loginlets an account continue to the code when it would otherwise be answered with a lock or a decoy (no passkey, locked or left with no allowed method) and holds an unused code.GET /system-config/publicreportsrecoveryCodes.recovery_codestable, andsessions.recovery.See docs/account-recovery.md.
5f41ee0:
OAUTH_ALLOW_UNBOUND_STATEis removed. Every OAuth callback must carry the binding/startreturned, as clients from@seamless-auth/client0.7.1 (@seamless-auth/react0.18.1,@seamless-auth/react-native0.3.3) do. A callback without one is refused with400 Invalid OAuth stateand audited asstate_binding_missing, whatever the variable says. A deployment that still sets it gets a boot warning that it is ignored.Breaking for any client older than those SDK versions that starts OAuth sign-in: upgrade it before this release.
4205828: The server's own secrets no longer fall back to the service token (feat(config): require each secret whose feature is in use, with no service token fallback #447).
REFRESH_TOKEN_LOOKUP_SECRETandDECOY_SUBJECT_SECRETare always required,TOTP_SECRET_ENCRYPTION_KEYonce any TOTP credential exists, andOAUTH_STATE_SECRETonce an OAuth provider is configured. The server refuses to start without the ones it needs and names each one.POST /system-config/oauth-providers, oroauth_providersinPATCH /system-config/admin) answers409 { "error": "secret_required", "variable": "OAUTH_STATE_SECRET" }while it is unset, andPOST /totp/enroll/startanswers the same forTOTP_SECRET_ENCRYPTION_KEY.Breaking for a production deployment that relied on the fallback: before upgrading, set each missing variable to the current service token value, so existing sessions, TOTP enrollments and OAuth sign-ins in flight stay valid. See docs/production-operations.md.
41071ea: Auth policy changes are versioned, can be staged as a draft, and can be dry-run and rolled back.
/system-config/policy: read the published version and draft, save or discard the draft, publish it, roll back to an earlier version, list versions, and dry-run a policy against recent sign-ins. Publish and rollback needadmin:writeand a fresh step-up, takeexpectedVersion, and answer409 policy_version_conflictwhen another version was published since.policy_versionstable, including a whole-configPATCH /system-config/adminthat changes a policy key (sourceconfig_patch). The first boot after upgrading records the policy in force as version 1 (sourcebootstrap). Run the migration before starting this release.BREAK_GLASS_EMAILSare counted, never listed.policy_draft_saved,policy_draft_discarded,policy_published,policy_rolled_backandpolicy_dry_run.The dry run also reports
authenticator_not_allowedandsynced_passkey_blockedfor an account holding a passkey the candidate authenticator policy would not admit at enrollment. Those passkeys keep signing in, so such an entry counts no refused sign-in and is neverlockedOut.894a8bf: Moves to
@seamless-auth/types0.30.0.clientSecretEnvdoes not end in_CLIENT_SECRETor a provider URL is nothttp(s), the same rules 0.19.4 enforced after parsing. The production-only checks (https, public destinations) stay in the server.recovery_codes(RECOVERY_CODES, default{"enabled":true,"requireAtEnrollment":false}) andaccount_recovery(ACCOUNT_RECOVERY, default{"enabled":false,"delay":"24h"}), seeded at boot and patchable. The recovery features that read them arrive in this release.Patch Changes
ea27343: Changing a user's email or phone through
PATCH /admin/users/{userId}now signs the user out and tells them (feat(admin): revoke sessions and notify when an admin changes a user's email or phone #475).internal_user_updated_by_owneraudit event recordsidentityChanges(SHA-256 digests of the previous and new values),revokedSessionsand the outcome of each notice.x-seamless-auth-delivery-mode: externalno notice is sent, because the delivery payload has no kind for account notices yet. Each is recorded asnot_sent_external_delivery.The response shape is unchanged.
c1b2226: Consume one-time credentials atomically. Email and phone OTPs are now cleared with an update conditional on the issuance that was compared, and a TOTP code is only accepted while the stored counter is still older than it, so concurrent submissions of one valid code yield exactly one success. TOTP enrollment enables the pending credential the same way. The losing request gets the same response and audit event as an invalid code.
7b5484c: OTP and magic link limits and links are scoped to the sign-in attempt, so a stranger who knows an address can no longer use up or void the owner's codes and links (fix(rate-limit): per-identity OTP and magic link buckets are shared by every attempt #468).
flow_rate_limits.*.perIdentityon the identifier plus the ephemeral token's attempt (jti), or the requester's IP when there is none. Another attempt for the same address keeps its own allowance.perIdentity(20 per window by default), so minting fresh attempts still cannot message an address without bound.POST /magic-linkexpires only earlier links from the same attempt instead of every link for the account.FLOW_RATE_LIMITS/flow_rate_limitskeep their shape and meaning. No new config key.e46987a: Update body-parser to 2.4.0 and ip-address to 10.7.4 to pick up fixes for GHSA-27r3-jxmh-p828 and GHSA-rxp7-6hxx-x8q5.
88ea07c: The bundled Docker Compose stack serves on loopback only and no longer grants admin to a fixed address (fix(compose): bind the bundled stack to localhost and drop the default owner #473).
docker-compose.ymlpublishes the API on127.0.0.1:${API_PORT:-5312}and no longer publishes Postgres. Docker's port publishing bypasses host firewalls such as ufw, so the old bare port exposed the development defaults to the network.POSTGRES_PORTno longer applies to this file; usedocker compose exec postgres psql -U seamless seamless_authfor a shell.docker-compose.dev.ymlpublishes the API and Postgres on127.0.0.1only.OWNER_EMAILtoowner@example.comany more. Pass your own, for exampleOWNER_EMAIL=you@example.com docker compose up; without it nobody is granted admin. An existing stack whose owner account was already created keeps its role.The release image now builds the admin dashboard from a pinned commit (
SEAMLESS_ADMIN_DASHBOARD_REF, dashboard v0.10.1) and refuses a build arg that is not a full commit SHA (ci: pin the release supply chain #474). Overriding it with a tag or branch name fails the build.9f6ba6b: OAuth sign-in respects the per-account passkey requirement (fix(oauth): OAuth sign-in skips the per-account passkey requirement #469).
passkey_login_fallback_enabledoff,POST /oauth/:providerId/callbackfor an account that holds a passkey now answers403 login_method_disabledand issues no session, as the email code, phone code, magic link and TOTP continuations already did. The refusal is recorded asoauth_login_failedwith reasonpasskey_required.bf48b20: Account recovery works with adapter-owned delivery, and a signed-in owner can cancel it.
POST /recovery/verifyreturns the "recovery opened" notices asdeliveries(account_notice_email/account_notice_sms, with thecancelUrl) to a credentialed caller that owns delivery and lists those kinds in the newx-seamless-auth-delivery-kindsheader. A caller that owns delivery but does not list them still gets503 recovery_notice_failed, since an older adapter would drop a kind it does not know. The adapter manifest marks the routenotices: true.POST /recovery/startcarriespurpose: "account_recovery"under external delivery.GET /recovery/requestsandDELETE /recovery/requests/:id(access session) list and cancel the account's open recovery requests without the token from the notice.@seamless-auth/typesto 0.31.0.4d2bc08: Self-service account recovery fails closed when the owner cannot be told.
POST /recovery/verifynow voids the request and answers503withrecovery_notice_failedunless the opening notice reached at least one verified address, and it cancels the account's other open requests only after that notice is sent. Before, a request opened even when every notice failed or was skipped for external delivery, so the delay ran without the owner ever getting a cancel link.d83d2ac: The registration email OTP path honours
login_methodsfor accounts that are already verified (fix(otp): registration email OTP signs in verified accounts whatever login_methods says #470).POST /otp/verify-email-otpsigns an already verified account in only whenemail_otpis a login method (and the passkey rules allow it). Otherwise it answers403 login_method_disabledbefore checking the code, the same answer as/otp/verify-login-email-otp. Before, a deployment that removedemail_otpfromlogin_methodscould still be signed in to with an email code through this endpoint.POST /otp/generate-email-otp(and its deprecatedGET) refuses an already verified account the same way, and its OpenAPI responses now list403.login_methodssays.ee9a575: Log out everywhere can no longer miss a session a concurrent refresh was creating (fix(sessions): log out everywhere can miss a session created by a concurrent refresh #471).
DELETE /logout/all,DELETE /sessions,DELETE /admin/sessions/:userId/revoke-all, device-replacement recovery and OAuth provider retirement revoke with one bulk update instead of reading the sessions and revoking them one at a time.POST /refresh, which re-reads the cutoff after claiming the rotation, so a rotation that started before the revoke cannot produce a live session. The refusal is401 invalid_refresh_token, withrefusal: 'sessions_revoked'on therefresh_token_failedauth event.usersgainssessions_revoked_before.