Docs/Guides/OAuth Providers

OAuth Providers

KATforge supports four social login providers plus its own first-party OAuth server:

ProviderIdentifierNotes
DiscorddiscordStandard OAuth 2.0
GooglegoogleStandard OAuth 2.0
AppleappleSign in with Apple
SteamsteamOpenID 2.0 (legacy)
KATforgekatforgeFirst-party OAuth 2.0 server with PKCE

Flow

The flow is two-legged. The frontend never sees the provider's code directly; the API handles the callback and redirects back with a result.

sequenceDiagram
    autonumber
    participant B as Browser
    participant A as KATforge API
    participant P as Provider (Discord/Google/...)

    B->>A: GET /v1/gateway/oauth/{provider}/url
    A-->>B: { url: "https://provider.com/oauth2/authorize?..." }
    B->>P: Redirect to provider authorization page
    P-->>B: Redirect back with ?code=...&state=...
    B->>A: GET /v1/gateway/oauth/{provider}/check?code=...&state=...
    A->>P: Exchange code for access token
    P-->>A: User profile
    A-->>B: 302 → frontend with access_token, needs_username, or error

1. Get the authorization URL

TypeScript
const { url } = await katforge.auth.oauthUrl ('discord', {
   redirect: 'https://katforge.com/oauth/callback'
});

window.location.href = url;

The redirect URL must be on a KATforge-owned domain. It's preserved across the entire round-trip.

2. Handle the callback

The browser ends up at your redirect URL with one of three outcomes encoded in the query string:

Success — existing user

text
https://katforge.com/oauth/callback?access_token=eyJ...&created=0

The refresh token is also set as a cookie on the response. Just use the access token; you're logged in.

Success — new user, needs username

text
https://katforge.com/oauth/callback?needs_username=1&temp_token=eyJ...&suggested_username=Anders&email=anders@example.com

Show a username picker, then call:

TypeScript
const session = await katforge.auth.oauthComplete ({
   temp_token: tempToken,
   username:   chosenUsername
});

This creates the new account and returns a normal TokenResponse.

Error

text
https://katforge.com/oauth/callback?error=Invalid+state

Just display the error to the user.

Linking and unlinking providers

Authenticated users can link extra providers to their existing account:

TypeScript
await katforge.auth.oauthLink ('discord', { code, state });

And remove them:

TypeScript
await katforge.auth.oauthUnlink ('discord');

The API refuses to unlink the last remaining sign-in method to avoid locking the user out.

Listing linked providers

TypeScript
const { providers } = await katforge.auth.oauthList ();
// providers: [{ provider: 'discord', linked_at: '...', external_id: '...' }, ...]

KATforge as an OAuth provider

KATforge can also act as an OAuth 2.0 provider for first-party and approved third-party apps. The flow is standard authorization-code with optional PKCE:

  1. Validate the client + redirect URI: GET /v1/oauth/authorize/validate?client_id=…&redirect_uri=…
  2. Authorize after user consent: POST /v1/oauth/authorize returns a code
  3. Exchange the code for tokens: POST /v1/oauth/token (grant_type=authorization_code)
  4. Read the user profile: GET /v1/oauth/userinfo

See the OAuth Server endpoints in the API reference for details.