feat(oauth): surface actionable callback failure codes#103
Merged
Conversation
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.
Closes #91.
What
The OAuth callback computed specific, user-actionable failure reasons and then discarded them, returning a generic
400 { error: 'OAuth login failed' }for all of them. It now returns a stable machine-readablecodealongside the existingerrorstring for the curated, user-actionable cases.oauthService.ts: newOAuthProfileError { code }thrown for the three curated conditions instead of bareError.oauth.ts(controller): thecatchmaps anOAuthProfileErrorto{ error, code }and records the specificreasonin the audit event; every other error keeps the generic{ error: 'OAuth login failed' }withreason: 'callback_failed'.oauth.responses.ts/oauth.routes.ts: dedicatedOAuthLoginErrorResponseSchemawith an optionalcodeenum wired to the callback 400 (the response validator strips unknown keys, so a dedicated schema is required forcodeto survive).Surfaced codes:
oauth_missing_email,oauth_email_not_verified,oauth_missing_subject.Deliberate scope limit
Only the curated set is exposed. Upstream detail (
OAuth profile fetch failed with status <n>, token-exchange failures, raw provider bodies) stays behind the generic message.Contract change / ripple
This adds a
codefield to the OAuth callback (POST /oauth/:providerId/callback) 400 response. The client side is already being prepared in fells-code/seamless-auth-react#83 (throws aSeamlessAuthErrorcarrying HTTPstatusand parsedbody), which can then mapbody.code. I will survey@seamless-auth/reactand@seamless-auth/serverfor concrete consume sites and propose coordinated edits separately; no sibling repo changes are included here.Acceptance criteria
codeerrorstring field preserved for backward compatibilitycallback_failedfor the known casesChecks
typecheck, lint, OAuth integration + unit suites, OpenAPI/route-schema tests all pass. Security review passed (no findings). Changeset included (
minor).