Repository navigation
fix(oauth): send the state binding back with the OAuth callback - #203
Merged
Merged
Conversation
The auth server can now bind the OAuth state to the client that started sign-in and refuse a callback without that binding. The session actions store the binding returned by startOAuthLogin with its state, attach it in finishOAuthLogin when the state matches, and clear it afterwards. startOAuthSignIn passes it explicitly on the in-app browser path and refuses a callback whose state differs from the one it started. Refs fells-code/seamless-auth-api#463
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.
Refs fells-code/seamless-auth-api#463
Client SDK half of binding the OAuth state to the client that started sign-in. Contract: fells-code/seamless-auth-api#465 (API) and fells-code/seamless-auth-types#104 (types), both unreleased.
What changes
POST /oauth/:providerId/startmay now returnbinding. The session actionstartOAuthLoginstores{ state, binding }insessionStorageunderseamless:oauth:binding(next toseamless:oauth:provider), with an in-memory copy for environments withoutsessionStorage(React Native) or with storage that refuses writes. A start response without a binding clears any stale one.finishOAuthLoginattaches the stored binding when the caller passed none and the callback'sstatematches the stored one, then clears it whether the callback succeeds or fails. An explicitbindingwins.createSeamlessAuthClient().finishOAuthLoginsendsbindingin the JSON body when present. It is never sent to the provider or put in a URL.startOAuthSignIn's in-app browser path passesdata.bindingexplicitly and refuses a callback whosestateis not the one it started.startOAuthLogin/finishOAuthLoginthroughuseAuth()(the seamless-templates react-oauth template, the admin dashboard) and the Angular, Vue and Svelte bindings get it with only an SDK upgrade.Types
StartOAuthLoginResultaliasesStartOAuthLoginResponsefrom@seamless-auth/types, which does not havebindingyet and cannot be bumped until types#104 is published. It is extended locally (StartOAuthLoginResponse & { binding?: string }), andFinishOAuthLoginInput(already local) gainsbinding?: string. Once types ships, the local extension can be dropped in favour of the upstream field.Compatibility and release order
Older auth servers return no binding, so nothing extra is sent and they are unaffected. API 0.19.x with #463 refuses a callback without the binding (
400 Invalid OAuth state), so this SDK must reach users before or with that API release.Release order: types (seamless-auth-types#104), then the API (seamless-auth-api#465), then this. Changesets are patch for
@seamless-auth/client,@seamless-auth/reactand@seamless-auth/react-native.Docs
The React, React Native and client READMEs describe the binding for manual integrations, and AGENTS.md notes the local type extension.
Checks
npm run typecheck: passnpm run lint: passnpm run format:check: passnpm test: Jest 47 suites, 618 tests pass; Vitest 3 files, 41 tests passnpm run build: pass (including the Angular, Vue and Svelte dist checks)