# Login & connecting a Baziness account

> How a player gets a Baziness identity, signs in from the splash screen or Settings, and how your game switches accounts safely.

## The identity model
Your game keeps **its own player accounts**, for example keyed by a device id generated on first launch. Baziness is attached **on top**:

1. The first time the platform is on, your server creates an **anonymous Baziness user** for the player ([`create-user`](platform-api.md#step-2-create-a-baziness-user-for-a-player)) and saves its `userId` on the player's record.
2. The player stays **anonymous** (`isLinkedToAccount: false`) until they sign in with their phone number on a Baziness page. The account is then **linked**.
3. If the Baziness account they sign into **already belongs to another of your players** (the same person on another phone), your game **switches** to that player. It doesn't link the account twice.

| State | Baziness `userId` saved? | `isLinkedToAccount` | What the player sees |
| --- | --- | --- | --- |
| Baziness off | — | — | no Baziness UI |
| Guest | yes (anonymous user) | `false` | coin balance and reward button work; "connect your account" in Settings |
| Signed in | yes | `true` | everything, including claiming Gita coin rewards |

## The whole flow
```mermaid
sequenceDiagram
  autonumber
  participant C as Game client
  participant S as Game server
  participant K as Platform API
  participant W as Baziness page (sheet)
  C->>S: GET /api/platform/config
  S-->>C: { enabled, webBase, apiBase, packageName }
  Note over C: Splash: Sign in with Baziness / Continue as guest
  C->>S: POST /api/platform/token { deviceId, linkedToken? }
  S->>K: create-user (first time) / get-user-token
  K-->>S: { userId, token, isLinkedToAccount }
  S-->>C: { token, bazinessUserId, isLinked, switchToDeviceId? }
  C->>W: open login page (sdkType=js, linkedToken, allowGuest=false)
  W-->>C: postMessage { type: "login", data: "<token>" }
  C->>S: POST /api/platform/login { deviceId, token }
  S->>K: validate-user-token
  K-->>S: { isValid, userId }
  S-->>C: { ok } — or { ok, switchToDeviceId }
  C->>C: close sheet, or switch device id + reload
```

## What your server provides
Your client never calls the platform's server API itself. It calls **three endpoints of your own server**:

| Your endpoint | The client sends | Your server does | It answers |
| --- | --- | --- | --- |
| `GET /api/platform/config` | — | nothing; it only reports settings | `{ enabled, webBase, apiBase, packageName, gameName, gameOfferUrl }`, or `{ enabled: false }` |
| `POST /api/platform/token` | device id, `linkedToken` if any | no Baziness user yet → `create-user`; otherwise → `get-user-token`. If the resulting `userId` belongs to another player, it does **not** link | `{ token, userId, isLinkedToAccount }`, or `{ switchToDeviceId }` |
| `POST /api/platform/login` | device id, the token from the sign-in page | `validate-user-token` → whose account is it? Another player's → switch; otherwise → link to this player | `{ ok: true }`, or `{ ok: true, switchToDeviceId }`, or `{ ok: false }` |

If the platform is unreachable, `/token` answers `{ enabled: true, error: "platform_unavailable" }` without a token, and the game boots anyway.

## The first launch: guest or sign in
When Baziness is on and the player has neither chosen yet nor signed in, the splash screen shows two buttons instead of the loading bar:

- **«ورود با حساب بازینس»** (sign in with Baziness): opens the sign-in page and waits.
- **«ادامه به عنوان مهمان»** (continue as guest): remembers the choice and continues.

The boot order:

1. Sign the player in to **your own** account system.
2. Ask your server for `/api/platform/config`. If Baziness is off, skip everything below.
3. If no choice was made and the player isn't signed in, show the two buttons and wait.
4. Call `/api/platform/token`. If it answers `switchToDeviceId`, adopt that id and restart.
5. If the player just signed in, load their profile again, so the screen shows the signed-in account.

If the player closes the sign-in page without signing in, show the two buttons again.

## Account switching, step by step
A switch happens when the Baziness account the player signs into is already linked to **another** of your players, for example after a reinstall or on a new phone:

1. Your server answers `switchToDeviceId: "<that player's device id>"`.
2. The client saves that device id as its own and forgets its stored Baziness token.
3. It restarts, without `linkedToken` in the address.
4. The next boot loads the other player, with all their progress.

## Opening the game from the Baziness app
> [!IMPORTANT]
> The Baziness app now also sends `?linkCode=` (one-time). Forward it to your server instead of `linkedToken`. See [Token migration](token-migration.md#client-steps).

The Baziness app opens games with `?linkedToken=<token>` in the address:

- Send that token as `linkedToken` to `/api/platform/token`, so the player lands in the right Baziness account. Remove it from the address on the next restart.
- If the device already holds a **different** token, a different Baziness account is arriving: clear the local data and start again before continuing.
- Signing in decides **which** account plays, never **whether the player is new**. A first-time player arriving this way must still see your tutorial and receive your welcome gifts.

## Signing in later, from Settings
A guest can connect their account at any time: Settings → open the **profile page** ([parameters](pages.md#the-pages)). When the view closes, ask `/api/platform/token` again and refresh the coin balance.

## Signing out
When the page sends `logout`, close the view, **delete everything your game stored locally** (identity, token, choices, tutorial progress) and restart as a brand-new visitor.

## Testing logins on the dev platform
> [!TIP]
> On the **development platform** (the one test games use), you can sign in with **any phone number** and the code **`111111`**. No SMS is sent. Make up numbers to create as many test accounts as you need: one for the account-switch test, one for a fresh guest, and so on. Production sends real SMS codes.

## Common mistakes
| Mistake | What happens | Fix |
| --- | --- | --- |
| Treating the page's `token` message as a sign-in | the reward shop closes as soon as it opens; the first sign-in completes before the player signs in | only `login` is a sign-in |
| Linking a token without `validate-user-token` | anyone can claim any account | always verify on the server |
| Opening the sign-in page without the player's token | the first sign-in from the splash has no anonymous user to bind to | make sure `/api/platform/token` ran first and pass its token as `linkedToken` |
| No `allowGuest=false` on the sign-in page | the player sees a second "continue as guest" | add it on the sign-in, profile and offer pages |
| Rewarding the link more than once | signing out and in pays again | pay the "account connected" gift from the server, once per player |

Ready-made code: [server endpoints](samples-server.md#login-endpoints), [client controller and messages](samples-client.md#platform-controller).
