Skip to content

fix(registration): send the response ttl as a number - #138

Merged
Bccorb merged 2 commits into
mainfrom
fix/registration-ttl-is-a-number
Jul 31, 2026
Merged

fix(registration): send the response ttl as a number#138
Bccorb merged 2 commits into
mainfrom
fix/registration-ttl-is-a-number

Conversation

@Bccorb

@Bccorb Bccorb commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Second of three. Draft: blocked on fells-code/seamless-auth-types#27.

Response bodies are validated against RegistrationSuccessSchema at runtime, so with the published types@0.5.0 (which still declares ttl: z.string()) this change makes registration return 500. The test suite catches that, which is how I confirmed the coupling. Verified against a local build of the fixed types package. The dependency bump is the last commit here before it comes out of draft.

The bug

Registration fails on the Fastify adapter with TypeError: option maxAge is invalid: 300, because this API sends ttl: '300' as a string and cookie requires Number.isInteger.

It was the only ttl this API sends that was not a number. The Express adapter multiplies it into milliseconds, which coerces the string, so the same response has always worked there and the mismatch went unnoticed.

The change

ttl: '300' becomes ttl: 300, with a comment recording the invariant that it has to match the 5m in signEphemeralToken. A caller sets its registration cookie from this value, so a larger number here would leave a cookie outliving the token it carries.

openapi.json and src/generated/api.ts regenerated: "ttl": { "type": "string" } becomes "type": "number". The contract test enforces it.

Scope I backed out

I first hoisted the lifetime into an exported EPHEMERAL_TOKEN_TTL_SECONDS so the 5m and the 300 collapsed into one value. Four test files mock src/lib/token.js, and each would have needed the new export added to its mock. That is a lot of test-infrastructure churn for what is a one-word type fix, so I reverted it and left the invariant as a comment.

Worth doing on its own: the two literals can still drift, and a comment is weaker than a shared constant. Happy to open it separately.

Verification

npm run typecheck, npm run test:run (91 files, all passing), npm run lint, npm run format:check all clean, against a local build of the types fix.

Bccorb added 2 commits July 31, 2026 09:11
It was the string '300', the only ttl this API sends that was not a number. A
caller sets its registration cookie from it, and the Fastify adapter passes the
value to a cookie library that requires an integer, so registration failed there
with `TypeError: option maxAge is invalid: 300`. The Express adapter multiplies
it into milliseconds, which coerces the string, so the same response worked and
the mismatch went unnoticed.

Response bodies are validated against the shared schema at runtime, so this
needs @seamless-auth/types 0.6.0, where RegistrationSuccessSchema.ttl becomes a
number. The dependency pin is bumped separately once that release lands.

Verified with npm run typecheck, npm run test:run (91 files passing), npm run
lint, and npm run format:check, against a local build of the types package.
openapi.json and src/generated/api.ts regenerated; the contract test enforces it.
The release where RegistrationSuccessSchema.ttl is a number. Response bodies are
validated against that schema at runtime, so the registration change on this
branch returned 500 against 0.5.0 and only works from here.

Verified against the published package with npm run typecheck, npm run test:run
(91 files passing), npm run lint, and npm run format:check. Re-running
npm run generate:api produces no diff, so the committed contract already matches
the published schema.
@Bccorb
Bccorb marked this pull request as ready for review July 31, 2026 17:38
@Bccorb
Bccorb merged commit f677f17 into main Jul 31, 2026
2 checks passed
@Bccorb
Bccorb deleted the fix/registration-ttl-is-a-number branch July 31, 2026 17:40
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.

1 participant