# Poll the sign-in status
URL: https://musicapi.com/docs/connect-users/poll-sign-in-status.md

> Start a sign-in with your own uniqueId and poll its state, for desktop apps, TVs and other clients that cannot receive a redirect.

Product: MusicAPI Core and MusicAPI Managed Transfers. Section: Connect your users.

Some clients cannot catch a redirect: a desktop app that opens the system browser, a TV app that shows a QR code, a CLI. Give the sign-in your own id and ask for its state until it ends.

1. **Make a UUID v4**

   Make it on the client, for example with `crypto.randomUUID()`. Use a new one for every sign-in.
2. **Open the sign-in with it**

   Add it as `uniqueId` to the sign-in URL, and open the URL in the browser.
3. **Poll**

   Call `GET /app/integrations/byUniqueId/{uniqueId}` every 2 seconds until `authModel.status` is `success` or `error`.

```url
https://app.musicapi.com/{slug}?returnUrl={returnUrl}&uniqueId=7f1d2b9a-3c4e-4f5a-8b6c-9d0e1f2a3b4c
```

```js
const uniqueId = crypto.randomUUID();
openBrowser(`https://app.musicapi.com/{slug}?returnUrl=${encodeURIComponent("{returnUrl}")}&uniqueId=${uniqueId}`);

async function waitForSignIn() {
  for (let i = 0; i < 150; i += 1) {
    const response = await fetch(`https://api.musicapi.com/app/integrations/byUniqueId/${uniqueId}?tokenOnly=1`);
    if (response.ok) {
      const { authModel, integrationUser } = await response.json();
      if (authModel.status === "success") return integrationUser.uuid;
      if (authModel.status === "error") throw new Error(authModel.errorType ?? "Sign-in failed");
    }
    await new Promise((resolve) => setTimeout(resolve, 2000));
  }
  throw new Error("Timed out");
}
```

```bash
curl "https://api.musicapi.com/app/integrations/byUniqueId/7f1d2b9a-3c4e-4f5a-8b6c-9d0e1f2a3b4c?tokenOnly=1"
```

## The answer

- `404` until the user picks a service: the attempt does not exist yet. Keep polling.
- `200` with `authModel.status: "initialised"` while the user signs in.
- `200` with `success` or `error` at the end.

```json
{
  "authModel": {
    "uuid": "a1869581-38b2-4268-aee2-a4c2355efeb0",
    "status": "success",
    "error": null,
    "errorType": null
  },
  "oneTimeToken": null,
  "integrationUser": {
    "uuid": "3f0b8c1e-6a4d-4c7a-9a55-2f1e7d9b0c11",
    "integrationUserId": "mica.nowak",
    "name": "Mica Nowak",
    "email": "mica@example.com",
    "imageUrl": "https://images.example.com/mica.jpg",
    "country": "PL"
  }
}
```

## Security

The call needs no credential: the `uniqueId` you chose is the secret. Treat it like a password for the length of the sign-in.

- Always make the `uniqueId` with a secure random generator, never from a user id.
- Send `tokenOnly=1` from a browser or any client you do not control. The answer then never holds music-service credentials.
- Without `tokenOnly`, a sign-in started with `requestOneTimeToken=true` whose `returnUrl` is not an `http(s)` URL (a native app scheme) also returns `authData`, the raw service tokens. A sign-in that returns to an `http(s)` URL never does.
- With `requestOneTimeToken=true`, `oneTimeToken` carries a token that lives 30 seconds.
