Set up credentials
Register your app with the provider:- Google — Google Cloud Console → APIs & Services → Credentials → OAuth 2.0 Client IDs. Authorized redirect URI:
https://your-app.com/api/auth/callback/google. - GitHub — GitHub Settings → Developer settings → OAuth Apps. Authorization callback URL:
https://your-app.com/api/auth/callback/github.
CLIENT_ID or CLIENT_SECRET is unset, that provider is silently disabled — /api/auth/providers won’t list it.
On Pylon Cloud, set these in Settings → Environment per workspace. Cloud also offers shared dev credentials in non-prod workspaces so you can prototype before registering your own.
How it works
Two ways to invoke
Browser flow (302 redirect)
GET /api/auth/login/google?redirect=1 returns a 302 directly to the provider. The callback handler sets a cookie and redirects to PYLON_DASHBOARD_URL. This is the simplest integration for a typical web app:
PYLON_DASHBOARD_URL=https://your-app.com so the callback knows where to send the user after sign-in.
JSON flow (manual)
For SPAs or native apps that want to control the redirect themselves:redirect, the user comes back to your app’s ?code=...&state=xyz URL, and you POST it to the callback:
From the SDKs
CSRF protection
Every OAuth start mints a random state token (256 bits, prefixedpylon_) that expires after 10 minutes and is single-use. The callback rejects the request if:
- The state is missing
- The state has expired
- The state was already used (replay)
- The state was minted for a different provider (e.g. Google state on a GitHub callback)
OAuthStateBackend so a server restart mid-handshake doesn’t break in-flight sign-ins.
What gets created
On first OAuth sign-in for a given email, Pylon creates aUser row:
emailVerified immediately. Your User entity should have:
Discovering configured providers
Provider-specific notes
- Scopes requested:
openid email profile - Userinfo endpoint:
https://www.googleapis.com/oauth2/v3/userinfo - Display name comes from
namefield
GitHub
- Scopes requested:
user:email - Userinfo endpoint:
https://api.github.com/user - Display name comes from
name, falls back tologin - If the user’s primary email is private, Pylon hits
/user/emailsto find a verified primary
Adding a new provider
The two built-in providers cover most cases. To add another (Apple, Microsoft, Discord, etc.) you have two paths: 1. As a plugin — register a custom OAuth handler in your app code (recommended for Cloud users):OAuthConfig in crates/auth/src/lib.rs with the provider’s URL constants. Ships with your binary; great if you’re self-hosting.
Error responses
| Code | Status | Meaning |
|---|---|---|
PROVIDER_NOT_FOUND | 404 | PYLON_OAUTH_<PROVIDER>_* env vars not set |
OAUTH_BAD_STATE | 400 | State missing, expired, or replayed |
OAUTH_PROVIDER_REJECTED | 400 | Provider returned an error during code exchange |
OAUTH_DASHBOARD_URL_MISSING | 500 | PYLON_DASHBOARD_URL not set for the GET callback redirect |