feat(api): add public Bind-Code onboarding for the player console
Adds POST /api/v1/auth/bind, the one public pre-account entrypoint of the player console (console.<root_domain>). An account-less player redeems the one-time Bind Code minted in the in-game Login Lobby; in a single step the platform creates a role=user player, links it to the verified in-game UUID, and mints a host-only felis_session. Login is thus not forced at the edge while operations stay app-authenticated. The operator console (op.console.<root_domain>) is unaffected and stays behind Zero Trust: a code whose UUID resolves to a staff (role=admin) account is refused with 403 (ErrPlayerBindForbidden) without consuming the code, so the public door provably never yields an admin principal — the session it mints carries ViaAdminAccess=false and is host-only to console, never sent to op.console. Repo layer: new RedeemPlayerBindCode on the Repo interface, implemented on PGRepo (single tx: resolve code, create-or-fetch the player, consume) and the test fake. The returning-player branch is idempotent and is a deliberate standing "log in via the game" door, not just first-time onboarding. Honest labeling: - ORACLE-VERIFIED (Go): account/session logic — role=user, refuse-staff, idempotent create-or-fetch, single-use code, and the op.console redline (player session rejected on admin routes). Covered by handlers_onboard_test and the OpenAPI parity gate. - INTEGRATION-dependent: the endpoint's security rests on the Bind Code having been minted against an online-mode-Yggdrasil-authenticated UUID, a precondition that lives in velocity/Java and is not verifiable from this repo (CODE-ONLY). The Go layer proves the logic, not that identity guarantee. - No app-level attempt cap: rate-limiting is deferred to the edge as for the public /auth/login; the ~1e12 keyspace, single use and short TTL make a blind app-level cap non-critical.
This commit is contained in:
8 files changed
+585
No files matched your search
@@ -1338,6 +1338,62 @@ paths:
|
||||
'403':
|
||||
$ref: '#/components/responses/Forbidden'
|
||||
|
||||
/api/v1/auth/bind:
|
||||
post:
|
||||
tags: [auth]
|
||||
operationId: bindRedeem
|
||||
summary: Redeem a Bind Code into a player account + session (public console bootstrap, spec §10/§B).
|
||||
description: >-
|
||||
The one public, pre-account entrypoint of the player console
|
||||
(console.<root_domain>): an account-less player redeems the one-time Bind
|
||||
Code they generated in the in-game Login Lobby, and the platform creates their
|
||||
player account (role=user), binds it to the verified in-game UUID, and mints a
|
||||
host-only session cookie. Safe to expose unauthenticated because the code is
|
||||
minted internal-face only, against an online-mode-verified UUID, with a short
|
||||
TTL and single use — possession already proves control of a Minecraft identity.
|
||||
An already-linked player UUID logs that player back in (idempotent); a UUID
|
||||
that belongs to staff is refused (403) — operators authenticate at op.console
|
||||
behind Zero Trust, so this never mints a session for an admin identity. Requires
|
||||
local sessions to be enabled (same toggle as login).
|
||||
x-felis-face: [external]
|
||||
x-felis-tier: public
|
||||
security: []
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [code]
|
||||
properties:
|
||||
code: { type: string }
|
||||
responses:
|
||||
'200':
|
||||
description: Player account bootstrapped; the session cookie is set on the response.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [user_id, linked, mc_uuid, auth_source]
|
||||
properties:
|
||||
user_id: { type: string }
|
||||
linked: { type: boolean, const: true }
|
||||
mc_uuid: { type: string }
|
||||
auth_source:
|
||||
type: string
|
||||
enum: [mojang, thirdparty]
|
||||
description: The source captured at mint, copied onto the durable link.
|
||||
'400':
|
||||
description: Invalid or expired bind code.
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/Error' }
|
||||
'403':
|
||||
description: Local sessions are disabled, or the code's UUID belongs to a staff account.
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/Error' }
|
||||
|
||||
/api/v1/me:
|
||||
get:
|
||||
tags: [servers]
|
||||
|
||||
Reference in new issue
Block a user