{"record":{"id":"ba4c8d9c9b15b6c3","repo":"anomalyco/sst","slug":"error","errorCode":null,"errorMessage":"error","messagePattern":"error","errorType":"exception","errorClass":"OauthError","httpStatus":null,"severity":"error","filePath":"sdk/js/src/auth/adapter/oauth.ts","lineNumber":103,"sourceCode":"          config.issuer.metadata.userinfo_endpoint\n            ? \"callback\"\n            : \"oauthCallback\"\n        ](callback.toString(), query, {\n          code_verifier,\n          state,\n        });\n        return ctx.success(c, {\n          client,\n          tokenset,\n        });\n      });\n\n      // response_mode=form_post\n      routes.post(\"/callback\", async (c) => {\n        const [callback, client] = getClient(c);\n        const form = await c.req.formData();\n        if (form.get(\"error\")) {\n          throw new OauthError(form.get(\"error\")!.toString());\n        }\n        const code_verifier = getCookie(c, \"auth_code_verifier\");\n        const state = getCookie(c, \"auth_state\");\n        const tokenset = await client[\n          config.issuer.metadata.userinfo_endpoint\n            ? \"callback\"\n            : \"oauthCallback\"\n        ](callback.toString(), Object.fromEntries(form as any), {\n          code_verifier,\n          state,\n        });\n        return ctx.success(c, {\n          client,\n          tokenset,\n        });\n      });\n    } satisfies Adapter<{\n      tokenset: TokenSet;","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/anomalyco/sst/blob/a0bd20f762883e72a35caccb4896c42ce5b3f707/sdk/js/src/auth/adapter/oauth.ts#L85-L121","documentation":"In the OAuth adapter's form_post callback route, if the identity provider POSTs an `error` field in the form body, the adapter rethrows it as an `OauthError`. This surfaces provider-side OAuth failures (per RFC 6749) such as `access_denied`, `invalid_request`, or `server_error` back to your handler with the raw provider error code as the message.","triggerScenarios":"An IdP POSTs to `/<auth-name>/callback` (response_mode=form_post) with `error` in the form body instead of `code`/`state`. Happens when the user denies consent, the authorization request was malformed, scopes are invalid, or the provider errors out during authorization.","commonSituations":"User cancels the consent screen (`access_denied`); misconfigured redirect URI or client ID (`invalid_request`, `unauthorized_client`); requesting scopes the app isn't approved for; IdP outage (`temporarily_unavailable`); expired or replayed authorization flow.","solutions":["Read `error.response`/the OauthError message to identify the provider error code and handle it (e.g. show a 'consent denied' UI for access_denied).","Verify your OAuth client config: client ID, secret, redirect URI, and requested scopes match the provider's registered values.","Restart the login flow from /authorize — OAuth errors on callback are not retryable with the same request.","Check the provider dashboard/logs for the corresponding authorization failure detail."],"exampleFix":"try {\n  await client.auth.<provider>.authorize(...)\n} catch (e) {\n  if (e instanceof OauthError && e.message === \"access_denied\") {\n    return new Response(\"You must grant access to continue\", { status: 403 });\n  }\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"// Check before redirecting to the IdP that client config is registered correctly\nconst redirect = await client.authorizationUrl({ redirect_uri, scope });\nif (!redirect) throw new Error(\"OAuth client not configured\");","typeGuard":"function isOauthError(e: unknown): e is OauthError {\n  return e instanceof OauthError;\n}","tryCatchPattern":"try {\n  await completeLogin(c);\n} catch (e) {\n  if (e instanceof OauthError) {\n    if (e.message === \"access_denied\") return c.text(\"Access denied by user\", 403);\n    return c.text(\"OAuth error: \" + e.message, 502);\n  }\n  throw e;\n}","preventionTips":["Always wrap OAuth callback handling in try/catch — provider errors are expected user behavior.","Register redirect URIs, scopes, and grant types exactly as requested in the provider dashboard.","Map provider error codes (access_denied, invalid_request) to user-friendly messages."],"tags":["auth","oauth","openid","identity-provider"],"backgroundTag":"oauth-provider-error","analyzedSha":"a0bd20f762883e72a35caccb4896c42ce5b3f707","analyzedAt":"2026-08-30T11:26:00.383Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}