Repository navigation
feat: deliver enrollment invites through adopter messaging, and keep the session when a refresh fails transiently - #273
Merged
Conversation
Parity scenarios for POST /admin/enrollment/invites across Express, Fastify and Next.js: the external delivery header and delivery service token when messaging is set, one message per results[].delivery with the payloads stripped, a failed delivery reported as delivery_failed while the rest send, and plain passthrough without messaging. Fails until #183 lands.
With messaging configured, POST /admin/enrollment/invites now requests external delivery with the external delivery service token and sends each results[].delivery through deliverAuthMessage. The payloads are stripped from the response. A recipient whose delivery throws is reported with the API's delivery_failed skip reason and the counts are adjusted, while the other recipients are still sent. The route is served from the manifest in every adapter, so the handling lives in core's handleManifestRoute. Closes #183
Parity scenarios for the silent refresh and cookie-transport POST /refresh in Express, Fastify and Next.js. A transport error, a non-401 answer, a 200 without a session and a rotated session that fails verification all clear the session cookies today (POST /refresh answers 500 for the last two). The auth API answering 401 and an unreadable refresh cookie still clear them. The existing forged-token scenarios now expect 502 with the cookies kept. A Next.js scenario pins that one caller aborting its request does not cancel a rotation another caller shares; it passes already, since no request's abort signal reaches the upstream call. Refs fells-code/seamless-auth-go#22
The silent refresh and cookie-transport POST /refresh cleared the session cookies on any failure. They are now cleared only when the auth API answers the refresh with 401 or the refresh cookie cannot be read. A transport error answers 502 upstream_unavailable, any other non-2xx answer passes through, and a rotated session that fails verification (or a 2xx without one) answers 502, all with the cookies kept. This matches the Go adapter's fix for fells-code/seamless-auth-go#22. Core gains refreshCookieSession, which reports how a cookie rotation ended; refreshAccessToken keeps its signature. In-flight sharing and the 5 second completed-rotation window are unchanged. Tests that pinned the old answers are updated, and the cookie security tests now serve a verifiable rotated token, since they had been reading the attributes of cookies cleared by a failed verification.
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.
Two changes, each with its tests committed first (
239b132anddc5e8a7fail onmain: 3 and 15 failures per adapter in the Fastify and Next.js parity suites).Closes #183
Enrollment invites through adopter messaging (#183)
POST /admin/enrollment/invitesis served from the manifest in all three adapters, so the change is in core (isEnrollmentInvitesinmanifestProxy.ts,deliverEnrollmentInvitesindeliverAuthMessage.ts).messagingconfigured, the request carriesx-seamless-auth-delivery-mode: externaland the delivery service token (subjectseamless-auth-external-delivery). Eachresults[].deliverygoes throughdeliverAuthMessageand is removed from the response, so addresses and links never reach the browser.{ status: "skipped", reason: "delivery_failed" }(sentdown,skippedup). The other recipients still send and the route answers 200.messagingthe route is unchanged.recently_invited(noted in the changeset).Refresh failures keep the session (parity with fells-code/seamless-auth-go#22)
Cookies are now cleared only when the auth API answers the refresh with 401, or the refresh cookie cannot be read. New
refreshCookieSessionin core reports how a rotation ended;ensureCookiesand the refresh handler use it.POST /refresh(cookie)Refresh failed(as before)invalid_refresh_token(as before)upstream_unavailableupstream_unavailableupstream_unavailableinternal_error)In-flight sharing and the cookie-only 5 second window are unchanged. One caller's abort cannot cancel a shared rotation in Node (only
AbortSignal.timeoutsignals exist and the shared promise lives in a module-level map); a new Next.js test aborts the first caller mid-rotation and the second still gets 200.Consequence, same as Go: if the rotated token fails verification (for example a wrong
authServerIssuer), the API has already spent the old refresh token, so the next attempt hits reuse detection and signs out. A misconfiguration shows as one 502 and then a sign-out.Checks
pnpm build;pnpm test: core 700, express 310, fastify 330, nextjs 361. One Express test (proxyQueryForwarding, route param encoding) failed once in a full run and passed on two reruns; it is unrelated.