ScalixScalix Docs
Sign up

OAuth Providers

Sign in with Google, GitHub, and custom OIDC providers (Apple, Microsoft, Auth0, ...)

Looking for how to connect ChatGPT, Claude or an IDE to your Scalix account? That is the opposite direction — Scalix acting as the OAuth provider — and it lives in Connect an app. This page is about signing your end users in with a third-party identity provider.

Supported Providers

ProviderStatus
GoogleAvailable
GitHubAvailable
Any OIDC providerAvailable (per-project, see below)

OAuth Flow

1. Initiate

Request an authorization URL:

bash
curl -X POST https://api.scalix.world/v1/auth/oauth/authorize \
  -H "Content-Type: application/json" \
  -d '{"provider": "google", "redirect_url": "https://myapp.com/callback"}'

Response:

json
{
  "url": "https://accounts.google.com/o/oauth2/v2/auth?...",
  "state": "csrf_state"
}

Redirect the user to the returned URL.

2. Callback

After the user authorizes, they're redirected to your callback URL with a code:

plaintext
https://myapp.com/callback?code=auth_code_here&state=csrf_state

3. Exchange

Exchange the code for tokens:

bash
curl -X POST https://api.scalix.world/v1/auth/oauth/callback \
  -d '{
    "provider": "google",
    "code": "auth_code_here",
    "redirect_url": "https://myapp.com/callback",
    "state": "csrf_state"
  }'

Response:

json
{
  "user": {
    "id": "usr_abc123",
    "email": "user@gmail.com",
    "is_anonymous": false
  },
  "session": {
    "access_token": "eyJhbGciOi...",
    "refresh_token": "a1b2c3d4e5...",
    "expires_in": 900,
    "token_type": "bearer"
  }
}

Client SDK

The auth SDK handles the OAuth flow:

typescript
import { ScalixAuthClient } from "@scalix-world/auth";
 
const auth = new ScalixAuthClient({ url: "https://api.scalix.world" });
 
// Returns an authorization URL
const { url } = await auth.signInWithOAuth("google", "https://myapp.com/callback");
window.location.href = url;
 
// After the IdP redirects back to your callback route:
const { user, session } = await auth.completeOAuthSignIn(
  provider, code, "https://myapp.com/callback", state,
);

Custom OIDC Providers (Apple, Microsoft, Auth0, ...)

Any OIDC identity provider can be registered per project — no platform release required. A provider is referenced everywhere as oidc:<slug>.

Register a provider (admin)

bash
curl -X POST https://api.scalix.world/v1/auth/admin/oidc-providers \
  -H "Authorization: Bearer $SCALIX_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "slug": "apple",
    "display_name": "Apple",
    "authorize_url": "https://appleid.apple.com/auth/authorize",
    "token_url": "https://appleid.apple.com/auth/token",
    "userinfo_url": "https://appleid.apple.com/auth/userinfo",
    "client_id": "com.your.app",
    "client_secret": "...",
    "scopes": ["openid", "email", "name"]
  }'

List and delete:

bash
curl https://api.scalix.world/v1/auth/admin/oidc-providers \
  -H "Authorization: Bearer $SCALIX_SECRET_KEY"
 
curl -X DELETE https://api.scalix.world/v1/auth/admin/oidc-providers/apple \
  -H "Authorization: Bearer $SCALIX_SECRET_KEY"

Rules: slug is 1–63 lowercase letters/digits/-/_, unique per project; all three endpoints must be https (http is accepted only for localhost — useful for Keycloak/Auth0 in dev); credentials are stored per project and never returned (client_secret reads back as "configured").

Sign users in

Once the provider row exists, use the normal OAuth endpoints with the composite provider name:

bash
curl -X POST https://api.scalix.world/v1/auth/oauth/authorize \
  -d '{"provider": "oidc:apple", "redirect_url": "https://myapp.com/callback"}'
typescript
const { url } = await auth.signInWithOidc("apple", "https://myapp.com/callback");
window.location.href = url;

The flow is the same code + PKCE (S256) exchange as the built-in providers, against the registered endpoints; the userinfo response is mapped on the standard sub / email / name / picture claims.

Note: unlike email sign-in, OAuth/OIDC sign-in is not filtered by allowed_providers (that list gates email, magic-link, and phone methods). Registering the provider row is what enables it, and deleting the row is what disables it.

POST for an existing slug returns 409 — delete the provider first if you need to change its configuration. The userinfo email_verified claim, when the provider emits it, is enforced; an account that links to an existing local email keeps the same takeover protections as the Google path.

Account Linking

If a user signs up with email/password and later signs in with Google using the same email, the accounts can be linked via the identity link endpoint:

bash
curl -X POST https://api.scalix.world/v1/auth/identity/link \
  -H "Authorization: Bearer $ACCESS_TOKEN"

Custom Claims in Tokens

Every access token carries the user's user_metadata and app_metadata objects (the same objects the profile APIs expose), so your backend can authorize on roles or plan flags without a second fetch:

json
{
  "sub": "usr_abc123",
  "role": "authenticated",
  "app_metadata": { "role": "admin", "tier": "pro" },
  "user_metadata": { "name": "Alice" }
}

role is read from app_metadata.role when set (default authenticated).