Sign in with dzbot
Let your players sign in to your own website or app with their dzbot account. They sign in on your server's dzbot page — linking their game account there if they haven't yet — confirm what your app may do, and land back in your app. You build no login, no account linking and no alt detection: dzbot is where your players are managed anyway.
// SetupSet up
In your server's admin area, open Developers, create an app and open its Sign in with dzbot tab:
- Redirect URIs — where dzbot sends the user back, e.g.
https://your-site.example/auth/callback. https only;http://localhostworks for development. - Browser origins — for apps that call the API from the browser, e.g.
https://your-site.example. - Client secret — only for apps with a backend (confidential clients). A browser-only app has none and relies on PKCE.
The sign-in works on the servers the app is enabled for. The token it produces is bound to the one server the user signed in on.
// PermissionsScopes are access rights
A scope is a dzbot access right, the same keys you see in the group editor — wildcards included: player.shop.*, player.tickets.create, admin.tickets.view. Who the user is (player, main account, linked accounts) needs no scope.
What a token may do is the overlap of three things: the scopes the user confirmed, the app's own rights ceiling, and the user's real rights on the server. A player who confirms admin.* hands over nothing an admin could do, because they cannot do it themselves.
The consent page lists every concrete right a request covers within the ceiling, and exactly those are granted — a wildcard is resolved at that moment, so rights added to dzbot or to the ceiling later need a new sign-in.
Some endpoints stay closed to sign-in tokens whatever their scopes: the account, OAuth and organization areas, faction actions, live rooms, the claim, event sign-ups, impersonation and magic links, the AI Companion and the developer apps themselves (403 app_token_path_not_allowed).
// No backendIn the browser
A public client: no secret, PKCE, tokens in sessionStorage. dzbot is your whole backend.
import { Dzbot, OAuthClient } from '@dzbot/sdk'
const oauth = new OAuthClient({
clientId: 'your-client-id',
redirectUri: 'https://your-site.example/auth/callback',
server: 'your-server',
})
// Sign-in button
location.href = await oauth.authorizeUrl({ scope: ['player.shop.access', 'player.shop.checkout'] })
// On /auth/callback
await oauth.handleCallback(location.href)
const dzbot = new Dzbot({ server: 'your-server', oauth })
const me = await dzbot.me()
console.log(me.player?.name, me.accounts)// With a backendOn a server
A confidential client with its secret. Give every browser session its own TokenStore (memory for a single process, Redis or your database otherwise) — the store keeps the pending sign-in between redirect and callback and the tokens afterwards.
const oauth = new OAuthClient({
clientId: process.env.DZBOT_CLIENT_ID,
clientSecret: process.env.DZBOT_CLIENT_SECRET,
redirectUri: 'https://your-site.example/auth/callback',
server: 'your-server',
store: sessionStore(req), // get(key), set(key, value), remove(key)
})The starter bot does exactly this with Express.
// SessionsTokens
| Method | Does |
|---|---|
authorizeUrl({ scope, state? }) | The URL to send the user to, on https://<server>.dzbot.de/oauth/authorize |
handleCallback(url) | Checks state, exchanges the code, stores the tokens. A refused consent throws OAuthError with code access_denied |
accessToken() | A valid access token, refreshed a minute before it runs out |
refresh() | Refreshes now; concurrent calls share one request. When dzbot refuses, the user is signed out (login_required) |
isSignedIn() / tokens() | Whether tokens are stored, and which |
revoke() | Signs out at dzbot and forgets the tokens |
Access tokens live one hour. Refresh tokens rotate on every use and live 30 days for confidential clients, 7 days for public ones. Users see and revoke connected apps on their profile.
// Any languageWithout the SDK
Standard OAuth 2 authorization code with PKCE (S256):
GET https://<server>.dzbot.de/oauth/authorize?response_type=code&client_id=…&redirect_uri=…
&scope=player.shop.access%20player.tickets.create&state=…&code_challenge=…&code_challenge_method=S256
POST https://api.dzbot.de/oauth/token (application/x-www-form-urlencoded)
grant_type=authorization_code&code=…&redirect_uri=…&client_id=…&code_verifier=…[&client_secret=…]
grant_type=refresh_token&refresh_token=…&client_id=…[&client_secret=…]
→ { token_type, expires_in, access_token, refresh_token, scope }
POST https://api.dzbot.de/oauth/revoke token=…Call the API with Authorization: Bearer <access_token> and the X-Server-Subdomain of the server the user signed in on; another server answers 401 token_server_mismatch.