Skip to main content

OAuth providers

IdentSphere ships built-in support for two social-OAuth providers: Google and GitHub. Both implement OAuth 2.1 authorization-code flow.

Configuration

Set the appropriate client ID + secret in AppConfig. Missing client IDs mean the corresponding provider's endpoint returns 404.

AppConfig {
oauth_google_client_id: Some("123-abc.apps.googleusercontent.com".into()),
oauth_google_client_secret: Some(std::env::var("GOOGLE_SECRET").unwrap()),
oauth_github_client_id: Some("Iv1.deadbeef".into()),
oauth_github_client_secret: Some(std::env::var("GH_SECRET").unwrap()),
..Default::default()
}

Redirect URI to register

Whatever provider you configure, register this exact callback URL in their OAuth app settings:

{public_base_url}/v1/auth/oauth/{provider}/callback

For public_base_url = https://auth.example.com and provider google:

https://auth.example.com/v1/auth/oauth/google/callback

Flow

[browser] [provider]
│ │
│ GET /v1/auth/oauth/google/start? │
│ redirect_to=/dashboard │
│ ──────────────────────────────────────► │ (307 redirect)
│ │
│ GET https://accounts.google.com/... │
│ ───────────────────────────────────────►│
│ │
│ user consents │
│ │
│ GET /v1/auth/oauth/google/callback? │
│ code=...&state=... │
│ ◄────────────────────────────────────── │
│ │
│ → IdentSphere exchanges code for tokens │
│ → IdentSphere looks up / creates user │
│ → IdentSphere sets session cookies │
│ → 307 redirect to /dashboard │

Identity matching

Provider-returned email is the linking key:

  • Existing users.email match → sign that user in to their existing org.
  • No match → create a fresh org with the user as owner, mark email_verified = true.

Google: the email is sourced from the ID token's email claim. The SDK validates the ID token against Google's JWKS.

GitHub: the email is sourced from /user, falling back to the primary verified address in /user/emails.

CSRF / state

A 32-byte random state token is minted at /start and persisted in session_cache under IdentSphere:oauth:state:{token} with a 10-minute TTL. The callback compares; missing or expired state is 400.

Open-redirect defense

The redirect_to query parameter is validated:

  • Must start with /.
  • Must NOT start with // (protocol-relative URL hijack).
  • Must NOT be an absolute URL.

If validation fails, the start endpoint returns 400.

Provider errors

If the provider redirects back with ?error=access_denied (user clicked "deny"), IdentSphere redirects back to your redirect_to with ?oauth_error=access_denied. Your frontend reads oauth_error from the URL to show the user a message.

Adding more providers

Apple, Microsoft, etc. are not in v0.1. The OAuth handler is structured to make adding more providers straightforward — file an issue if you need one soon.

Audit

Every successful callback emits an audit entry:

  • auth.oauth.google.linked for Google
  • auth.oauth.github.linked for GitHub

Metadata includes existing_user: true/false.