Skip to content

feat(oauth): read the returnTo a sign-in asked for and land on it - #146

Merged
Bccorb merged 1 commit into
mainfrom
feat/oauth-return-to
Sep 7, 2026
Merged

feat(oauth): read the returnTo a sign-in asked for and land on it#146
Bccorb merged 1 commit into
mainfrom
feat/oauth-return-to

Conversation

@Bccorb

@Bccorb Bccorb commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Completes the returnTo chain. seamless-auth-types 0.20.0 added the response field and
seamless-auth-api populates it; this reads it.

The whole callback body was being discarded

startOAuthLogin has taken a returnTo since OAuth landed here, and nothing ever read one
back. The auth server validated it against the configured origins and signed it into the
state, but finishOAuthLogin was typed as a bare MessageResult, so an adopter had no way
to learn where the flow had been asked to end up.

It now resolves to FinishOAuthLoginResult, the completed OAuth response minus its session
material, for the same reason LoginStartResult drops it: sessions are carried by cookies,
so there is no reason to hand an adopter raw tokens. The new field is returnTo, absent when
the caller asked for nothing.

The bundled view lands there

OAuthCallback navigated to / unconditionally. It now goes where the flow asked.

This is the same gap the magic link redirect closed in 0.10.0, and for the same audience: the
headless client could reach the feature and an application using AuthRoutes could not,
which is the audience least likely to be wiring up its own client.

The view only follows a destination on its own origin. That is not the guard against an
open redirect, which the auth server already applied before signing the state. It is
narrower: these views route with react-router, which cannot leave the application, so another
origin is not somewhere this component can send anyone. An adopter that wants to reads
returnTo off the result and navigates itself.

Worth noting the origin check does double duty. A javascript: URL parses but resolves to a
null origin, so it is refused here as well, on top of RedirectTargetSchema refusing it at
the API and allowedReturnTo refusing it by origin comparison. Three independent layers now,
none of them relied upon alone.

Dependency

@seamless-auth/types moves from ^0.16.0 to ^0.20.0. Nothing else in the four releases
touched anything this package consumes: typecheck, lint and the full suite were clean on the
bump alone before any of this change was written.

Checks

npm run typecheck, npm run lint, npm run format:check clean. 324 tests pass across 32
suites, up from 321. OAuthCallback coverage goes from 92.85 to 95.23 statements, with the
new cases covering the round trip, a cross-origin destination, an unparseable one and a
javascript: one.

Not included

Nothing here navigates cross-origin on an adopter's behalf, and no view reads returnTo other
than OAuthCallback. The magic link views still land on /; that flow has its own redirect
mechanism and is untouched.

startOAuthLogin has taken a returnTo since OAuth landed here and nothing ever read
one back. The auth server validated it against the configured origins and signed
it into the state, but finishOAuthLogin was typed as a bare MessageResult, so the
whole callback body was discarded and an adopter had no way to learn where the
flow had been asked to end up.

finishOAuthLogin now resolves to FinishOAuthLoginResult, the completed response
minus its session material, for the same reason LoginStartResult drops it:
sessions are carried by cookies, so there is no reason to hand an adopter raw
tokens.

The bundled OAuthCallback view lands there instead of always going to /. This is
the gap the magic link redirect closed in 0.10.0: the headless client could reach
the feature and an application using AuthRoutes could not.

The view only follows a destination on its own origin. That is not the guard
against an open redirect, which the auth server applied before signing the state.
It is that these views route with react-router, which cannot leave the
application. An adopter that wants to reads returnTo off the result and navigates
itself.
@Bccorb
Bccorb merged commit bd26c22 into main Sep 7, 2026
3 checks passed
@Bccorb
Bccorb deleted the feat/oauth-return-to branch September 7, 2026 22:39
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