← Back to blog

Seamless Auth v0.19: Fewer Promises, More Proof

· Brandon Corbett · 1 views
seamlessreleasesecuritypasswordless

Most releases are about what a project can do. v0.19 is about whether you should believe it.

The goal for this milestone was written at the top of the planning issue: make what Seamless Auth already does trustworthy and findable, and fix what strangers trip on. Almost nothing in it is a new feature. A lot of it is evidence.

The auth API is at 0.19.3. The SDKs, server adapters, admin dashboard, templates, and CLI all shipped matching releases, and the compatibility matrix lists exactly which versions go together.

Security fixes, all disclosed

Two findings were handled privately and fixed in 0.19.0, then published as advisories with 0.19.0 as the patched version:

  • GHSA-9jg2-jjqq-3346 (high). A magic link could issue a session to whoever was polling for it, more than once. Each link now issues exactly one session, to the sign-in attempt that requested it. A link opened on a different device asks the person who opened it to confirm before anything is issued.
  • GHSA-66gq-4pwg-33jq (medium). Anyone who knew your email could trigger account lockout with wrong codes, and the lock also blocked your passkeys. Passkey sign-in is no longer subject to lockout. A passkey assertion cannot be guessed, so locking it out only ever helped the attacker.

Two older advisories, fixed back in 0.8.0, were also published so the record is complete.

Then, while writing the RFC 9700 conformance matrix later in the milestone, we found a third: the OAuth state was signed and single use but not bound to the browser that started the sign-in. That is a login CSRF. It is fixed in 0.19.2, and I wrote it up separately because how we found it is the more useful part.

Around those, the API got stricter in ways you will only notice if something was wrong already:

  • A response that does not match its declared schema is no longer sent. The server answers a generic 500 and logs the mismatch.
  • Access and pre-auth tokens must carry the right audience and type. Service tokens must expire within an hour.
  • The server refuses to start in development mode when its issuer or origins point at a public host.
  • At boot it names every secret that is quietly sharing the service token, because rotating that token would otherwise sign everyone out. That fallback goes away in v0.20.

You cannot strand your own instance

The last admin can no longer be deleted, demoted, or delete themselves. The API answers 409 last_admin instead. A user still cannot delete their last passkey either, and device replacement recovery stays the path for someone who lost every credential.

This is the kind of guardrail nobody asks for until the day they need it, and then it is the only thing they care about.

From npx to a signed-in admin, without reading logs

The first-run experience had one embarrassing step: creating the first admin meant digging a one-time code out of the container logs. seamless owner-code now prints it.

We timed the quickstart exactly as the docs describe it, on clean machines:

MachineTime to an admin session
Linux x64, fresh runner63 s
Linux arm64, fresh runner50 s
macOS arm64, images cached29 s

Every run ended with the owner holding admin rights and nobody reading a log. The templates moved to the current SDKs, and the starter dev containers stopped writing root-owned files into your project on Linux, which had made a fresh project impossible to delete without sudo.

seamless migrate entra-id also landed in CLI 0.25, for importing users straight from Microsoft Entra ID.

Documentation that shows its work

This is the part of v0.19 I care about most.

  • Security posture and threat model. What the API defends against, what it does not, and the risks we accept on purpose, with every control linked to the code at a pinned release tag. Including the per-instance limits you hit when you run more than one replica.
  • OAuth client and RFC 9700. Every client recommendation in the OAuth 2.0 Security Best Current Practice, row by row, including the ones we only partly meet.
  • FIDO2 server self-validation. The FIDO Alliance's own conformance tools, run against 0.19.3: 159 passed, 0 failed, with the tests that did not run and why. It is self-validation, not certification, and the page says so.
  • Production checklist, signed container images with verification steps, and a SECURITY.md that says where to report.
  • A license pledge and a governance document, so "Apache-2.0" comes with a statement of how it stays that way.
  • Comparisons with Auth0 and Keycloak that open with when to choose them instead, and date every fact about the other product.

The docs repository is public now too, so every one of those pages can be checked, corrected, and argued with in the open.

Upgrading

Upgrade the auth API and the client SDK together: OAuth sign-in on 0.19.2 and later needs @seamless-auth/client 0.7.1 or newer. The v0.19 release notes have the full order, and a deprecated escape hatch for clients you cannot upgrade on the same day.

What is next

v0.20 removes the deprecated fallbacks this release warns about, and adds step-up authentication on the admin writes that can change who controls an instance. Further out, v0.21 makes Seamless Auth an OpenID Provider, which is when the authorization-server half of that RFC 9700 matrix starts being scored instead of listed.

Passwordless is not the hard part. Being believable is. v0.19 was about that.

© 2026 Seamless Auth