Public Access
feat(steam): verify the Steam ID with Sign in through Steam
The Steam ID is no longer typed in at registration or in the settings. A logged-in user links it through Steam OpenID 2.0: Auth checks the answer with Steam (check_authentication) and stores the ID as verified (V11 steam_id_verified). A one-time state plus a binding cookie tie the callback to the browser that started the link, so a foreign Steam login link cannot move someone's Steam ID into another account. Typed-in IDs from before stay unverified; a verified link from another account takes them away. DELETE /api/users/steam-link unlinks.
This commit is contained in:
1 parent
e3433799f1
commit
4b2acef381
44 files changed
+1079
-449
No files matched your search
@@ -26,7 +26,12 @@ To Be Played is split into three repositories:
|
||||
token that comes back revokes all tokens of that login. Logout revokes them too.
|
||||
- CSRF guard: `POST`, `PUT` and `DELETE` need an `X-TBP-Client` or `Authorization` header, and CORS allows only the
|
||||
frontend origin. A `Bearer` header still works for API clients and tests.
|
||||
- User settings: display name (unique, case-insensitive), Steam ID, language, dark mode.
|
||||
- User settings: display name (unique, case-insensitive), language, dark mode.
|
||||
- Steam account linked through **"Sign in through Steam"** (Steam OpenID 2.0, no API key), never typed in. Steam
|
||||
proves the SteamID64, and Auth asks Steam to confirm the answer (`check_authentication`) before it stores the ID
|
||||
as verified. A one-time state plus a binding cookie tie the answer to the browser that started the link, so a
|
||||
foreign Steam login link cannot move someone's Steam ID into another account. IDs typed in before this stay, but
|
||||
unverified: a verified link from another account takes them away. Unlinking is possible.
|
||||
- Appearance settings synced across devices: accent color, corner style, wide layout, background and dashboard
|
||||
banner from the user's own game art. Only whitelisted presets and Steam app ids are stored, never raw CSS or URLs.
|
||||
- Opt-in public profile at `/u/<display name>`. Auth answers with a short-lived **profile ticket** (EdDSA JWT,
|
||||
@@ -42,7 +47,10 @@ To Be Played is split into three repositories:
|
||||
| `POST` | `/api/auth/refresh` | refresh cookie, replaces both cookies |
|
||||
| `POST` | `/api/auth/logout` | refresh cookie, clears both cookies |
|
||||
| `GET` | `/api/users/me` | access token |
|
||||
| `PUT` | `/api/users/settings` | access token, sets a new access cookie |
|
||||
| `PUT` | `/api/users/settings` | access token |
|
||||
| `POST` | `/api/users/steam-link` | access token, returns Steam's login URL and sets the binding cookie |
|
||||
| `DELETE` | `/api/users/steam-link` | access token, removes the Steam ID and sets a new access cookie |
|
||||
| `GET` | `/api/steam-link/callback` | public, Steam's redirect back; binding cookie; redirects to the frontend settings |
|
||||
| `PUT` | `/api/users/settings/appearance` | access token |
|
||||
| `GET` | `/api/public/profiles/{displayName}` | public |
|
||||
| `GET` | `/api/stats/public` | public |
|
||||
@@ -101,6 +109,28 @@ sequenceDiagram
|
||||
3. On a `401` the frontend calls `POST /api/auth/refresh` once and sends the request again.
|
||||
`RefreshTokenService` replaces the refresh token. A replaced token that comes back revokes the whole login.
|
||||
|
||||
### Steam link flow
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant B as Browser (Frontend)
|
||||
participant A as Auth
|
||||
participant S as Steam
|
||||
B->>A: POST /api/users/steam-link (logged in)
|
||||
A-->>B: Steam login URL, Set-Cookie tbp_steam_link (state, 10 min)
|
||||
B->>S: Sign in on steamcommunity.com
|
||||
S-->>B: Redirect to /api/steam-link/callback?state=...&openid.*
|
||||
B->>A: GET callback with tbp_steam_link
|
||||
A->>S: check_authentication (openid.* sent back)
|
||||
S-->>A: is_valid:true
|
||||
A-->>B: Redirect to /settings?steam=linked
|
||||
B->>A: POST /api/auth/refresh (new steamId claim for Core)
|
||||
```
|
||||
|
||||
`SteamLinkService` checks the state against the binding cookie before it asks Steam anything, and uses each state
|
||||
once. `SteamOpenIdService` checks mode, endpoint, `return_to` and the signed fields, then asks Steam.
|
||||
`UserService.linkVerifiedSteamId` stores the ID and takes it from an account that only typed it in.
|
||||
|
||||
## Run locally
|
||||
|
||||
Needs Java 25 and Docker.
|
||||
@@ -125,6 +155,8 @@ Configuration comes from environment variables:
|
||||
| `JWT_KID` | Key id written into the token header |
|
||||
| `AUTH_INVITATION_CODE` | Code required for registration |
|
||||
| `DB_PASSWORD` | Local PostgreSQL password |
|
||||
| `APP_PUBLIC_URL` | Auth's public address, the Steam OpenID realm (default `http://localhost:8080`) |
|
||||
| `APP_FRONTEND_URL` | Where the Steam link ends (default `http://localhost:5173`) |
|
||||
|
||||
Generate a keypair:
|
||||
|
||||
|
||||
Reference in new issue
Block a user