GET /v1/auth/oauth/:provider/callback
The provider redirects here after the user consents (or denies). Exchanges the authorization code for a user identity, creates a user + organization if needed, and issues a browser session.
::: tip Auth Required: none. Validated state token IS the credential. :::
Request
GET /v1/auth/oauth/:provider/callback?code=...&state=...
| Path param | Notes |
|---|---|
provider | Must match the provider used in /start. |
| Query param | Notes |
|---|---|
code | Provider-issued authorization code. |
state | The state token issued by /start. |
error | If the provider returns an error here, IdentSphere redirects back to the original redirect_to with ?oauth_error=.... |
Response
307 Temporary Redirect (success)
Location is {public_base_url}{redirect_to} (the path captured at
/start). Session cookies are set: identsphere_at, identsphere_rt, identsphere_csrf.
307 Temporary Redirect (provider error)
Location is {public_base_url}{redirect_to}?oauth_error={percent_encoded}.
Your app reads oauth_error from the query string to display a message.
Error responses
| Status | Code | When |
|---|---|---|
| 400 | invalid_input | State missing, state expired, provider mismatch between start and callback, or code missing. |
| 401 | authentication_required | Provider rejected the code exchange, OR the matched user account is disabled. |
| 404 | not_found | Unknown provider OR provider not configured. |
| 500 | internal_error | Network, JSON parsing, or DB failure. |
Notes
- New users get a fresh organization (
ownerrole) and haveemail_verifiedset totrue(the provider already verified the address). - Existing users with the same email are signed into their existing organization — no second org is created.
- An audit entry (
auth.oauth.google.linkedorauth.oauth.github.linked) is recorded. - The state token is single-use; it is invalidated at the top of the callback regardless of outcome.
- The session is minted at AAL1 with
auth_method: "social_oauth".