Detailed references

v3 · Preview

Framework v3 is an opt-in preview available to everyone. New games use the stable framework by default.

External game client authentication

A framework v3 game can let players sign in with Boardweaver from an external client, such as a future Godot desktop app. The game's creator needs the Professional plan. Players need a Boardweaver account, but no paid plan. Platform admins also have this entitlement.

Framework v3 is an opt-in preview available to everyone. This feature supplies authentication and permission enforcement, not a Godot addon, native exports, matchmaking, or the bundled frontend's commit compatibility checks.

Register a client

A game administrator opens Game clients under Access in the studio. Register one public OAuth client per game with its callback URL. A public client has no secret: never put a developer session token in a shipped game.

Desktop callbacks use a loopback IP, such as http://127.0.0.1:3000/callback or http://[::1]:3000/callback. The authorization request may use a different port; its host, path and query must match the registered callback. HTTPS callbacks are also supported. URLs with credentials or fragments and HTTP callbacks on other hosts are refused.

Registration follows the plan of the game's creator (its earliest admin member), not that of the collaborator registering it. Only v3 games can register. Disabling a client revokes all its grants and pending authorization codes. Re-enabling it requires the creator's Professional entitlement and does not restore revoked grants.

The management API requires a first-party session token:

Request Body or query Result
POST /api/game-clients { gameDefinitionId, redirectUris: [...] } OAuth registration, including client_id, callback URLs and scope.
GET /api/game-clients?gameDefinitionId=<id> Game administrator only. { eligibility: { creatorEntitled, frameworkV3 }, client }, where client is { clientId, disabled, redirectUris } or null.
PUT /api/game-clients/<clientId> { disabled: true } or { disabled: false }. { success: true }.

The grant scope is play:<gameDefinitionId>. Dynamic MCP client registration at /register cannot create a game client or obtain a play grant.

Browser sign-in with PKCE

  1. Generate a cryptographically random PKCE verifier and an independent state. Derive the S256 challenge: SHA-256 of the verifier, encoded as base64url without padding.
  2. Open the system browser at Boardweaver's /authorize endpoint with response_type=code, client_id, redirect_uri, state, code_challenge, code_challenge_method=S256 and the registered scope. Omit resource for play grants.
  3. Boardweaver asks the player to sign in and approve access. The consent screen uses the registered game's name and designer, and describes game-only access.
  4. The callback receives code and state, or error=access_denied. Check state against the original attempt before accepting it. Bind a desktop callback listener only to loopback, close it after use, and implement cancellation and a timeout.
  5. Exchange the code at POST /token, using application/x-www-form-urlencoded with grant_type=authorization_code, client_id, code, code_verifier and the exact redirect_uri used in step 2. The ephemeral port must also match. There is no client_secret.

Authorization codes expire after ten minutes and can be redeemed once. Tokens use the standard OAuth response fields: access_token, refresh_token, token_type=bearer, expires_in=3600 and scope.

Keep refresh tokens in the operating system's secure credential store. The game should never collect a Boardweaver password.

Refresh, logout and revocation

Access tokens last one hour. Refresh tokens expire after 60 days and rotate on every use. Send a form-encoded POST /token with grant_type=refresh_token, client_id and refresh_token. Persist the replacement refresh token securely before discarding the old one.

Serialize refresh attempts. A used refresh token is invalid, including a concurrent replay. If a refresh response is lost and the old token has been consumed, start browser sign-in again. Refresh cannot expand the grant's scope. Previously issued access tokens remain valid until their expiry unless the grant is revoked.

Each successful sign-in creates a separate grant, so signing out one install does not sign out another. LogOut over the authenticated socket revokes that grant and all its access and refresh tokens. OAuth clients may also POST to /revoke with client_id and an access or refresh token.

Players manage their grants at Account settings > Connected games. Their first-party session can also call:

Request Result
GET /api/game-clients/connections { connections: [{ id, clientId, gameDefinitionId, name, createdAt }] }.
DELETE /api/game-clients/connections/<grantId> Revokes only the caller's grant.

The creator's entitlement, client availability and grant are checked when issuing or refreshing tokens, on authenticated socket requests, and before subscription updates. A creator downgrade blocks external-client access until the entitlement is restored. Deleted or disabled clients cannot obtain MCP credentials instead.

Connect to the socket

Open Boardweaver's /ws WebSocket using TLS in production. Send SetClientId first, then attach the current access token to every request:

{
  "requestId": "a-client-generated-request-id",
  "token": "<play-access-token>",
  "data": {
    "type": "SetClientId",
    "params": { "clientId": "an-install-or-connection-id" }
  }
}

A play-authenticated SetClientId response contains data.playUser, with the player's public id, username, avatar and creation date. It contains no private params.user, email, plan, studio permissions or account-wide match list, and cannot redeem a browser's readable sign-in token.

A socket keeps its first authenticated scope and game. It cannot switch between a session and play token or between games; those attempts fail with SCOPE_MISMATCH. A refreshed access token for the same game is accepted. Missing, expired or revoked play credentials authorize no play requests.

The socket sends match updates only while the last access token it received is valid, even when the client sends nothing. After each refresh, send SetClientId again with the new access token before the old one expires. When that token expires, the socket stops receiving updates without an error. Send the new token and Subscribe again to resume them.

The currently allowed requests are:

  • SetClientId, LogOut, Unsubscribe.
  • CreateMatch, naming this game and a version channel, or a rematch source in this game.
  • Subscribe, for this game's matches only.
  • JoinMatch, StartMatch, CommitDecision, LeaveMatch, SetMatchFocus, ReportMatchActivity, SetSpectatorPolicy, SetMatchAudioSettings, GetMatchReplay, StopWatching.
  • GetMatchSteps, GetMatchDraft, SaveMatchDraft, SetMatchSeen, Undo.
  • FetchMatchFeedbackForm, SubmitMatchFeedback, DismissMatchFeedback.

Use GetMatchSteps to read the steps of a live or finished v3 match. GetMatchReplay returns the finished match's replay metadata.

Every match target must belong to the grant's game. Private beta matches require game membership. Event tables are excluded. Successful CreateMatch, JoinMatch and Subscribe requests bind existing seats to the external client and lock the lobby's game selection. A subscription does not create seats for spectators. A rejected request or subscription batch leaves seat bindings unchanged. Other allowed requests authorize game access without binding seats or locking game selection.

Studio, admin, account-wide and MCP requests, and subscriptions to other models such as me, user or worktree, are refused. Play tokens do not authenticate first-party HTTP routes or /mcp. Match permissions such as host-only starting and legal moves still apply. The v3 gameplay protocol supports multi-step decisions and replay.

Need a hand with this?

Join our Discord