Skip to content

refactor: serve passthrough routes from the manifest and align guard and 404 responses - #268

Merged
Bccorb merged 1 commit into
mainfrom
fix/adapter-route-parity
Nov 2, 2026
Merged

Bccorb merged 1 commit into
mainfrom
fix/adapter-route-parity

Conversation

@Bccorb

@Bccorb Bccorb commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

Closes #263.

The JS adapters now route, refuse and log the way the Go, Python and Rust adapters do.

Passthrough routes come from the manifest

The static passthrough tables are deleted: proxyWithIdentity in Express, and PROXY_ROUTES in Fastify and Next.js (40 routes). Before deleting them, I compared every entry against the bundled manifest and against seamless-auth-api main. Method, path and credential match for each one except POST /users/update. The auth API has no such route, so the adapter was forwarding to a 404, and no client in the ecosystem calls it. That route is dropped.

What changes for those routes, now that handleManifestRoute serves them:

  • Token stripping: cookie-transport bodies drop token and refreshToken.
  • Upstream path: the request goes to the manifest's path, so /webAuthn/... becomes /webauthn/.... The API routes these case-insensitively, and /webauthn is its own spelling.
  • Raw downloads: these are recognised by content type instead of a per-route raw flag. The CSV and NDJSON exports still stream.
  • Dot segments: a dot segment in a path parameter answers 404 not_found instead of 400 bad_request, which is what the Go adapter answers. No upstream call is made either way.
  • Recovery refresh: Express and Fastify now apply the recovery-enrollment refresh to manifest routes, as Next.js already did. A recovery session that verifies POST /totp/enroll/verify is still rotated at once, and the existing recovery parity test covers it through the manifest path.

The dedicated handlers for admin users, sessions, system config and internal metrics stay. They turn failures into { error, details } (readUpstreamFailure), where the manifest proxy forwards the API's body verbatim. Moving them would change error bodies that callers read today.

The four handlers that pass an incomplete session body through now strip tokens in cookie transport: OTP verify, magic link poll, magic link verify (which gains a transport option) and organization switch.

Guard and 404 responses

Case Before Now
requireAuth, missing credential 401 "Failed to find authentication token required" 401 unauthenticated
requireAuth, invalid or ephemeral token 401 "Invalid or expired session" 401 unauthenticated
requireRole, role not granted 403 "Insufficient role" plus required and actual 403 insufficient_role
requireRole, user with no roles 403 "User has no roles assigned" 403 insufficient_role
requireRole, nothing authenticated 401 "Authentication required" 401 unauthenticated
Express, unmatched /auth/* path next() (app's own 404, HTML by default) 404 not_found (JSON)

The codes are now set in core (UNAUTHENTICATED, INSUFFICIENT_ROLE), so the Next.js guard no longer remaps them.

Logger

setSeamlessLogger and SeamlessLogger are exported from express, fastify and nextjs, and documented in each README. Every console.warn and console.error in the three bindings goes through getSeamlessLogger(). Fastify's own request.log calls stay as they are. The unhandled-route-error line is now a single string, with the redacted detail appended.

Manifest drift check

scripts/check-adapter-manifest.mjs compares the bundled manifest's routes with the ones seamless-auth-api main publishes, ignoring apiVersion. The new manifest workflow runs it on PRs, on pushes to main and daily, matching the Go, Python and Rust repos. Today the bundled copy (API 0.21.0) lists the same 130 routes as main (0.21.1).

Release

Changeset: minor for core, express, fastify and nextjs. The changeset body describes the response changes.

Tests

  • Parity (Fastify vs Express, Next.js vs Express): an unknown path answers the same JSON 404 on both. A former passthrough route (GET /organizations) strips tokens from its cookie-transport body. The Next.js guard parity now compares error bodies as well as statuses, across every refusal scenario.
  • Express:
    • requireRole bodies are asserted exactly, with no roles echoed.
    • Unknown paths answer a JSON 404.
    • Former passthrough routes strip tokens in cookie transport, and keep them in bearer transport.
    • /users/update is no longer served.
  • Fastify: the role guard's body is asserted exactly.
  • Core: each of the four incomplete-body handlers is tested in both transports.
  • Logger: in each binding, a warning reaches a logger set through that package's own setSeamlessLogger, and not console.
packages/core test: Tests:       616 passed, 616 total
packages/express test: Tests:    270 passed, 270 total
packages/fastify test: Tests:    274 passed, 274 total
packages/nextjs test: Tests:     315 passed, 315 total

The conformance workflow runs on this PR.

Downstream

seamless-auth-docs build/express-without-jwt.mdx quotes the old requireAuth bodies. It needs a follow-up edit once this releases. No other sibling repo matches the old strings.

…and 404 responses

Delete the static passthrough tables in the three bindings so those routes
come from the adapter manifest, which strips tokens from cookie-transport
bodies. Express and Fastify apply the recovery enrollment refresh to manifest
routes, as Next.js already did. POST /users/update is dropped: the auth API
has no such route.

requireAuth answers 401 unauthenticated and requireRole answers 403
insufficient_role without echoing roles. Express answers unmatched auth paths
with a JSON 404. OTP verify, magic link verify and poll, and organization
switch strip tokens from incomplete cookie-transport bodies.

setSeamlessLogger is re-exported from each binding, and the bindings log
through it. A manifest workflow checks the bundled manifest against the auth
API's.

Closes #263
@Bccorb
Bccorb merged commit bdf2160 into main Nov 2, 2026
6 checks passed
@Bccorb
Bccorb deleted the fix/adapter-route-parity branch November 2, 2026 00:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

refactor: serve passthrough routes from the manifest and align guard and 404 responses

1 participant