Skip to the content
  1. Docs
  2. Connect your users

Poll the sign-in status

Core + Managed TransfersGuide · 1 min
Start a sign-in with your own uniqueId and poll its state, for desktop apps, TVs and other clients that cannot receive a redirect.

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.

Sign-in URL with uniqueId
https://app.musicapi.com/{slug}?returnUrl={returnUrl}&uniqueId=7f1d2b9a-3c4e-4f5a-8b6c-9d0e1f2a3b4c
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");
}

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.
200 OK
{
  "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": "[email protected]",
    "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.