Auth
Complete an OAuth Login
The redirect target the OAuth provider sends the browser back to; validates state, exchanges the code, and opens a dashboard session.
GET
OAuth callback (provider redirects here)
The provider redirects the browser here after the user consents. The server
validates the returned
A failed exchange, an unverified email, an expired (older than 10 minutes) or
missing state cookie, or a login error all answer
state against the recurso_oauth_state cookie set by
GET /auth/oauth/{provider}/start
(constant-time compare), exchanges code for a token using the bound PKCE
verifier, fetches the user’s profile, and requires a verified email (Google:
email_verified is true; GitHub: a primary, verified email).
It then finds or creates the account:
- An existing linked identity logs in.
- An existing user with the same verified email is linked to the new identity and logged in.
- A brand-new email creates a tenant and its owner user, the same as
POST /auth/register.
recurso_session cookie — identical to a
password login — and 302s to the dashboard root.
On any failure other than a state mismatch it 302s to
{DASHBOARD_URL}/login?error=oauth; the redirect target is always the
configured dashboard URL, never a caller-supplied one. The state cookie is
cleared whichever way the attempt ends, so each start is single-use.
You do not call this endpoint yourself — register it as the provider’s
redirect URI (https://api.recurso.dev/auth/oauth/{provider}/callback).
Path Parameters
Query Parameters
Example Request
Example Response
There is no response body. A successful login answers302 Found with the
session cookie:
302 Found with Location: https://app.recurso.dev/login?error=oauth.
Errors
Errors use the standard envelope — see Errors.