Use your app's login

Let members use the login your website already has, with no second account or sign-in screen.

If your community site already has its own login, members don't need a second account for Domino. Your server tells Domino who is signed in, and their quests and progress follow the login they already use.

  • What members see. They sign in to your site as usual. There is no Domino sign-in screen. They can still link wallets and connect X or Discord accounts.
  • What you do in Console. An organization admin creates the server key under Settings → App login keys and keeps it working there. Reviewers can unlink a member's app identity on the member's page.
  • What your developer does. Adds a small handler to your site's server and points the browser at it.

Signing users in with Privy, Dynamic or Para? Their recipes give the whole server route: Privy, Dynamic, Para. For Reown AppKit, which has no login token, see Use Domino with Reown AppKit.

Fresh Domino-hosted apps can use the member sign-in supplied with their setup instead, including wallet sign-in where the project enables it. Domino's own wallet sign-in works only in apps Domino hosts; an app you host signs wallets in with its own login, as wallet sign-in in your own Next.js app shows.

Connect your app's login

Create an integration key

An organization administrator opens Settings → App login keys in Console, selects the project and environment, and registers the app's exact HTTPS origin. A Test key can also name a loopback origin, such as http://localhost:3000, for local development. To let tracker records name your app's user IDs, also fill in Identity kind; see link your app's user IDs. Expiry is Never expires unless you choose 30 days, 90 days or 1 year.

For a Domino-hosted app, leave Also save it as an app secret checked. Console stores the new key as the app secret APP_IDENTITY_KEY in the key's environment, and nobody copies it. Change App secret name if your server reads another name. The app reads the key from its next build: the next staged build in Test, or the next build promoted to live. The box needs publish permission and appears only for a project whose code Domino hosts.

For any other app, or with the box cleared, Console shows the key once. Save it directly in the application's server secrets as APP_IDENTITY_KEY.

A key belongs to one project and environment and signs members in only there. A Domino-hosted app's staging build runs in Test, so it needs a Test key registered for its staging address, https://<project-slug>--staging.domino.page. The live app needs a Live key for its live address or custom domain. Console refuses a key for a Domino address in the environment that address doesn't serve, and names the right one; see pick the environment.

Connect your server

Use createParticipantBackend from @domino-sdk/relay/portal-proxy. Its authenticate(request) function must verify the app's existing session and return a stable user ID. Mount the handler at /relay/*.

Connect the browser

Use createBrowserRelayClient({ baseUrl: "/relay" }) in the browser. The adapter supplies the registered project scope. You do not need to forward browser project headers or write your own identity exchange.

The complete server example explains routing, cookies, and error handling.

If your app signs members in or out without loading a new page, tell the browser client each time:

  • After your app's sign-in succeeds, read the Domino session again before showing member pages. The page read it when it loaded, while nobody was signed in, and keeps that answer until it is asked again. Otherwise the member looks signed out for up to 30 seconds, or until the window regains focus.
  • After your app's sign-out succeeds, read the session again too. With your app's session gone, Domino finds nobody signed in and the member's data disappears as soon as that read answers. Sign out through your app only: Domino's own sign-out passes through your server's check of the app session, so while that session lasts, the page's next read signs the member straight back in.

Verify through the app

  • Sign in normally and check that Domino recognizes the member.
  • Sign in without reloading the page and check that member pages show the member at once.
  • Complete one quest and refresh.
  • Sign out of your app and confirm that member access is removed.
  • Sign out without reloading the page and check that the member's data is gone without waiting for a poll.
  • If the app supports account switching, check that too.

Troubleshoot sign-in

Pick the environment for the address

Create the key in the environment whose members the app signs in:

The app's addressCreate the key in
Staging build, https://<project-slug>--staging.domino.pageTest
Development preview, https://<project-slug>--<session>.domino.pageTest
Live app, https://<project-slug>.domino.pageLive
Your custom domain, which serves the live appLive
Your own server's addressEither. Pick the environment its members belong to.
http://localhost:<port>, http://127.0.0.1:<port> or http://[::1]:<port>Test

For a staging, preview or live domino.page address in the other environment, Create server key refuses with a message that names the right environment, such as "…is a staging app, which signs members in to Test. Create this app login key in Test." Keys created before this check are left as they are; Disconnect one and create it again in the right environment.

The address must be an exact origin: https:// and the host, with an optional port, and nothing after it. When it has a path, a query or a trailing slash, Console names the origin it accepts, such as "Use the exact origin https://app.example.com, without a path, query or trailing slash." Plain http:// works only on a loopback host and only in Test: elsewhere Console answers "Use an HTTPS origin, or a loopback origin such as http://localhost:3000 for a Test key.", and on a Live key "Live app login keys need an HTTPS origin. Loopback origins such as http://localhost:3000 work only on Test keys."

Why Domino refused a sign-in

When Domino refuses the sign-in exchange, createParticipantBackend answers the browser with Domino's status and code. Only a 409 and ACCOUNT_VOUCHING_OFF carry Domino's own message; every other refusal shows a general one, so your users never read instructions meant for your developer.

StatuscodeMeaningWho fixes it
401IDENTITY_INTEGRATION_ACCESS_DENIEDThe key is unknown, expired or revoked, or isn't an app login key.Your developer sets a working key from Console as APP_IDENTITY_KEY.
400INVALID_IDENTITY_EXCHANGEThe server sent something besides a user ID, previousToken and up to 20 accounts.Your developer.
403ACCOUNT_VOUCHING_OFFThe server sent accounts, but the key doesn't vouch for accounts.An admin turns on vouching, or your developer stops sending accounts.
403live-offlineThe project's live app is offline because it has no plan.The organization chooses a plan.
409APP_IDENTITY_UNLINKEDAn organizer unlinked this user ID.An organizer relinks it.
409APP_IDENTITY_CONFLICTThe key already signs this user ID in as another member.An organizer.
429IDENTITY_INTEGRATION_ACCESS_DENIEDToo many sign-ins for this key. The answer's Retry-After says how many seconds to wait.Nobody: retry after the wait.

After sign-in, a participant request answers 403 IDENTITY_INTEGRATION_ACCESS_DENIED, "Application origin does not match the identity integration", when the origin your server passes to createParticipantBackend is not the key's origin. Create a key for the address the app runs at.

The key alone picks the project and environment for these requests. On the private staging address, they don't need the staging pass that a hosted app's own /relay/* proxy forwards, so app login works there as it does on the live address. A 403 staging-access-required comes from a request without the key.

Test the login in a browser

A browser test can run your real server handler, identity exchange included, against the fake participant API instead of Domino. Your app can then run at a local address such as http://127.0.0.1:4173 or vite dev's http://localhost:5173.

Develop against Domino on localhost

To run your app on your machine against real Domino, create a Test key for its local address, such as http://localhost:3000, and give createParticipantBackend the same origin with baseUrl: "https://relay.domino.run". Members sign in to the project's Test environment. A Live key needs an HTTPS origin, so create a separate Live key for the deployed address.

Each port is its own origin: a key for http://localhost:3000 refuses requests from http://localhost:3001. Wallet sign-in in your own Next.js app walks through it.

Your servers can report activity for your own users, such as a game reporting a win for user 42, and a quest can pay the member who signs in as that user. To allow it, give the key an identity kind, such as app:game, when you create it.

The key then links each user ID your server signs in to its member, as an identity of that kind in the project and environment. Your servers can send tracker records that name those user IDs, and Console lists them on the member under Identities.

An identity kind is for your app's own user IDs. To pay a member's Telegram, X or Discord account, vouch for it instead: X quests and Telegram and Discord trackers then pay it as an account the member linked.

  • A kind belongs to the key that first claimed it. In a project and environment, a kind names the user IDs of one app. While its key is connected, no other key can be created with it. Another project, or the other environment, has its own.
  • The kind is set when the key is created. It cannot be added to or changed on an existing key. Rotating the key keeps it and every link.
  • A user ID is linked when the user signs in. Records for a user ID nobody has signed in with yet are skipped. A linked user ID always signs in as its member.
  • Name the kind app: and up to 40 lowercase letters, digits, _ or -.

Leave the kind empty for an integration that only signs users in.

Map members to your user IDs

Your server can look up the member a user ID is linked to, and list the user IDs linked to each member, with the management client. Both read only linked user IDs: one an organizer unlinked is not found until it is relinked.

Reuse a kind after disconnecting its key

Disconnect keeps the kind's links: tracker records that name those user IDs still pay their members. A new key can take the kind only by adopting its identities, because each linked user ID then signs in as its member, and another app's user 42 would sign in as this app's user 42.

When you type a kind whose disconnected key left identities, Create server key shows how many user IDs it links. Adopt them only if the new key's user IDs mean the same users: check This app's user IDs mean the same users and give a reason, which the audit log keeps with your identity. Without adoption the key is refused; use a new kind for a different app. A kind with no identities left is reused freely.

A reviewer can unlink a member's app identity in Console, on the member under Identities. Unlinking:

  • stops tracker records that name the user ID from paying anyone, and removes it from the member's identities that new attempts read;
  • ends the member's sessions that the kind's key started for that user ID;
  • refuses that user ID's sign-in until it is relinked, so the user cannot reach the member through your app.

Relink restores it for the same member and rechecks the tracker records that were skipped while the user ID was unlinked. The quest's historical activity policy decides what happens to earlier activity: it is admitted automatically, or kept for the member or staff to release. Attempts already admitted keep their original attribution. Unlink and relink both need a reason and Review permission, and the audit log keeps both. See operator identity changes.

When Domino refuses a sign-in, your site can show the member why. createParticipantBackend answers the browser with status 409 and one of these codes:

codeMeaning
APP_IDENTITY_UNLINKEDAn organizer unlinked this user ID. Ask them to relink it.
APP_IDENTITY_CONFLICTThis key already signs the user ID in as another member than the one the kind links it to. Only an organizer can resolve it.

Vouch for your members' accounts

If your app already knows its users' X, Telegram or Discord accounts or wallets, its server can attach them when it signs each user in. Members then don't have to connect them again. X quests and Telegram and Discord trackers pay them from that moment, as if they had linked the accounts themselves. This is the same trust as a member import, for members who join after it.

Turn it on

Vouching is off for every key. An organization admin who also has Publish permission turns it on in Settings → App login keys: under Connected apps, choose Allow vouching on the key, give a reason, and confirm. The audit log keeps your identity and reason. Stop vouching turns it off the same way. Accounts already vouched for stay.

Allow it only when your app verifies the accounts it sends, because Domino trusts them like accounts the member proved.

What Domino does with each account

  • Attached. The account is linked to the member. Console marks it Vouched by and your key's name, under the member's Identities or Wallets.
  • Already linked. The member has it already. Nothing changes, so your server can send the same accounts every time it signs a user in.
  • Refused. It belongs to another member, or the member already has a different X, Telegram or Discord account. An account an organizer unlinked from this member, or the member disconnected, is refused too, so your app never undoes an unlink. A wallet is also refused when the member already has 5 wallets of that chain besides the one they sign in with.

A refused account never stops the sign-in. Domino tells your server which accounts it refused and why.

Vouched accounts follow the rules of imported ones:

  • A vouched account never replaces an account the member linked, nor one vouched for earlier.
  • When the member links an account of that kind themselves, their link replaces the vouched one.
  • Nobody signs in with a vouched account.
  • When an organizer unlinks a vouched account the member never signed in with or proved, Domino releases it: its owner can link it and sign in with it, and your app's next exchange can't vouch it back for that member. See operator identity changes.
  • A leaderboard's payout list leaves out vouched wallets. When the member links the wallet through Domino, signing Domino's own message in your app with relay.wallets.link, it becomes a wallet they proved and the payout list includes it. See pay prizes to the wallet.

Maintain the connection

A key has one or more secrets, and each works until it is revoked or reaches its own expiry. Each key in Connected apps lists its secrets with their last four characters, when they expire and when they were last used. A key created before secrets could be rotated keeps its original expiry until you remove it.

ActionEffect
Add secretIssues a second secret that never expires. Both secrets work. With Also save it as an app secret checked, Console replaces the app secret with the new secret; deploy to use it. Otherwise copy the new one with Copy key, update APP_IDENTITY_KEY on every server, and deploy. Member sessions stay signed in.
Revoke, then Revoke secretStops one secret at once. Wait until its Last used time stops changing first. A key's only secret has no Revoke.
Remove expiryMakes an expiring secret never expire.
Disconnect, then Disconnect nowStops every secret and ends the integration's member sessions.

On this page