From eb1084631ffab38ff9bb744787500f7b44ddac18 Mon Sep 17 00:00:00 2001 From: Brandon Corbett Date: Fri, 31 Jul 2026 09:11:44 -0400 Subject: [PATCH 1/2] fix(registration): send the response ttl as a number 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. --- .changeset/registration-ttl-is-a-number.md | 14 ++++++++++++++ openapi.json | 6 +++--- src/controllers/registration.ts | 5 ++++- src/generated/api.ts | 4 ++-- 4 files changed, 23 insertions(+), 6 deletions(-) create mode 100644 .changeset/registration-ttl-is-a-number.md diff --git a/.changeset/registration-ttl-is-a-number.md b/.changeset/registration-ttl-is-a-number.md new file mode 100644 index 0000000..0ec4852 --- /dev/null +++ b/.changeset/registration-ttl-is-a-number.md @@ -0,0 +1,14 @@ +--- +'seamless-auth-api': patch +--- + +Send the registration response's `ttl` as a number. + +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. + +Requires `@seamless-auth/types` 0.6.0, where `RegistrationSuccessSchema.ttl` becomes a number. +Response bodies are validated against that schema at runtime, so the two move together. diff --git a/openapi.json b/openapi.json index 8461913..a849e9b 100644 --- a/openapi.json +++ b/openapi.json @@ -1,6 +1,6 @@ { "openapi": "3.0.3", - "info": { "title": "Seamless Auth API", "version": "0.6.0" }, + "info": { "title": "Seamless Auth API", "version": "0.7.0" }, "components": { "schemas": {}, "parameters": {}, @@ -5415,7 +5415,7 @@ "message": { "type": "string" }, "sub": { "type": "string" }, "token": { "type": "string" }, - "ttl": { "type": "string" }, + "ttl": { "type": "number" }, "delivery": { "oneOf": [ { @@ -5455,7 +5455,7 @@ "message": "string", "sub": "string", "token": "string", - "ttl": "string", + "ttl": 0, "delivery": null } } diff --git a/src/controllers/registration.ts b/src/controllers/registration.ts index ac5d183..fd1d2b2 100644 --- a/src/controllers/registration.ts +++ b/src/controllers/registration.ts @@ -158,7 +158,10 @@ export const register = async (req: Request, res: Response) => { message: 'Success', sub: user.id, token, - ttl: '300', + // Seconds, and it has to match the `5m` in signEphemeralToken. A caller + // sets its registration cookie from this, so a larger value here leaves a + // cookie outliving the token it carries. + ttl: 300, ...(delivery ? { delivery } : {}), }); } catch (error: unknown) { diff --git a/src/generated/api.ts b/src/generated/api.ts index 6b027d1..0f98e0e 100644 --- a/src/generated/api.ts +++ b/src/generated/api.ts @@ -5769,7 +5769,7 @@ export interface paths { * "message": "string", * "sub": "string", * "token": "string", - * "ttl": "string", + * "ttl": 0, * "delivery": null * } */ @@ -5777,7 +5777,7 @@ export interface paths { message: string; sub?: string; token?: string; - ttl?: string; + ttl?: number; delivery?: | { /** @enum {string} */ From c129a258144bf2cfba9df708c73a6d0be46ab149 Mon Sep 17 00:00:00 2001 From: Brandon Corbett Date: Fri, 31 Jul 2026 13:32:17 -0400 Subject: [PATCH 2/2] chore(deps): move onto @seamless-auth/types 0.6.0 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. --- package-lock.json | 12 ++++++------ package.json | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 241cfd8..4540aa9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,19 +1,19 @@ { "name": "seamless-auth-api", - "version": "0.6.0", + "version": "0.7.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "seamless-auth-api", - "version": "0.6.0", + "version": "0.7.0", "license": "AGPL-3.0-only", "dependencies": { "@asteasolutions/zod-to-openapi": "^8.4.3", "@seamless-auth/messaging": "^0.1.0", "@seamless-auth/messaging-aws": "^0.1.0", "@seamless-auth/messaging-twilio": "^0.1.0", - "@seamless-auth/types": "^0.5.0", + "@seamless-auth/types": "^0.6.0", "@simplewebauthn/server": "^13.1.1", "base64url": "^3.0.1", "bcrypt-ts": "^7.1.0", @@ -3393,9 +3393,9 @@ } }, "node_modules/@seamless-auth/types": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@seamless-auth/types/-/types-0.5.0.tgz", - "integrity": "sha512-T566YQu8FqUmqgte0A0iJpjTDXUKq/d/7uvLlXGXKtdl52Edo0r3iafL3kx4OM0cRJM63tBGe9s4MTjRUth6yA==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@seamless-auth/types/-/types-0.6.0.tgz", + "integrity": "sha512-jsgSn6gAKFXpdKdQ0B4GconuKNWTQihCZLqqHmKYztolN4c3zMnrWrK3nQHup2a7q/TLxlk25HDZw2j4WxkjOA==", "license": "AGPL-3.0-only", "dependencies": { "zod": "^4.3.6" diff --git a/package.json b/package.json index 0062b60..bb9a120 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "@seamless-auth/messaging": "^0.1.0", "@seamless-auth/messaging-aws": "^0.1.0", "@seamless-auth/messaging-twilio": "^0.1.0", - "@seamless-auth/types": "^0.5.0", + "@seamless-auth/types": "^0.6.0", "@simplewebauthn/server": "^13.1.1", "base64url": "^3.0.1", "bcrypt-ts": "^7.1.0",