Docs / Authentication

Authentication

Asobi supports username/password, OAuth/OIDC social login (Google, Apple, Microsoft, Discord), Steam, and device auth. Players can link multiple providers to a single account.

Username & password

The simplest method. Register to receive a session token:

curl -X POST http://localhost:8082/api/v1/auth/register \
  -H 'Content-Type: application/json' \
  -d '{"username": "player1", "password": "secret123"}'
{"player_id": "...", "session_token": "...", "username": "player1"}

Use the session token in subsequent REST calls:

Authorization: Bearer 

Login reuses the same shape at /api/v1/auth/login.

OAuth / social login

For game clients, Asobi uses server-side token validation. The client authenticates with the platform SDK, obtains an ID token (JWT), and sends it to Asobi:

curl -X POST http://localhost:8082/api/v1/auth/oauth \
  -H 'Content-Type: application/json' \
  -d '{"provider": "google", "token": "eyJhbGciOiJSUzI1NiIs..."}'

Flow: platform SDK → ID token → Asobi validates against provider JWKS → existing player (login) or new one (create + link).

Supported providers

 Provider   | provider value | Issuer
------------|----------------|--------------------------------------------------
 Google     | "google"       | https://accounts.google.com
 Apple      | "apple"        | https://appleid.apple.com
 Microsoft  | "microsoft"    | https://login.microsoftonline.com/common/v2.0
 Discord    | "discord"      | https://discord.com
 Steam      | "steam"        | custom (Steam Web API session ticket)

Provider configuration

Add credentials to sys.config:

{asobi, [
    {oidc_providers, #{
        google => #{
            issuer => <<"https://accounts.google.com">>,
            client_id => <<"YOUR_CLIENT_ID">>,
            client_secret => <<"YOUR_CLIENT_SECRET">>
        },
        apple => #{
            issuer => <<"https://appleid.apple.com">>,
            client_id => <<"YOUR_CLIENT_ID">>,
            client_secret => <<"YOUR_CLIENT_SECRET">>
        }
    }}
]}

Steam

Steam uses session tickets rather than OIDC. The client calls ISteamUser::GetAuthSessionTicket and sends the hex-encoded ticket:

curl -X POST http://localhost:8082/api/v1/auth/oauth \
  -H 'Content-Type: application/json' \
  -d '{"provider": "steam", "token": "14000000..."}'

Asobi validates via the Steam Web API. Config:

{asobi, [
    {steam_api_key, <<"YOUR_STEAM_WEB_API_KEY">>},
    {steam_app_id, <<"YOUR_STEAM_APP_ID">>}
]}

Linking providers

Players can link additional providers to their existing account (Google + Steam on the same player, say). Requires an authenticated session:

curl -X POST http://localhost:8082/api/v1/auth/link \
  -H 'Authorization: Bearer ' \
  -H 'Content-Type: application/json' \
  -d '{"provider": "discord", "token": "eyJhbGciOi..."}'

Unlink via DELETE /api/v1/auth/unlink. Asobi refuses to unlink the last auth method to avoid locking the player out.

WebSocket authentication

After obtaining a session token (via any method above), connect to the WebSocket and authenticate as the first message:

{"type": "session.connect", "payload": {"token": ""}}

Token behaviour is provider-agnostic — it works the same regardless of which login path produced it.

SDK integration

Lua

-- Defold (Lua)
local id_token = google_sign_in.get_id_token()
asobi.auth.oauth("google", id_token, function(result)
    -- session token stored internally
end)

C#

// Unity (C#)
string idToken = googleSignIn.IdToken;
var response = await asobi.Auth.OAuth("google", idToken);
// session token stored internally

Where next?