Solana wallets
Sign people in with a Solana wallet, using Sign In With Solana.
Every brand offers Solana wallets. A person signs in by signing a request their wallet shows them; their wallet's address is who they are at the brand, and they need no email address. amr is wallet.
How it works
- The issuer makes the request. Each time the wallet page shows, the issuer writes the whole Sign In With Solana request: its own host as the domain, a statement naming the brand, the chain, a 128-bit nonce and a 5-minute window. Nothing in it comes from the browser.
- The wallet signs it. The page finds the browser's wallets through the Wallet Standard and lists each with its icon. A wallet that supports
solana:signInsigns the request as a sign-in, and checks its domain against the page; any other signs the same message as text (solana:signMessage), and the page asks the person to check that it names the site first. - The issuer checks it. A signature counts only if it's the address's own, over exactly the message the request makes, for this sign-in, within its window. The request is then spent: a signature replayed elsewhere is refused.
A request that expires while the page is open is replaced, not refused. Someone who declines in their wallet can choose again.
What to know
- Chains. The request names the stage's chain: devnet on preview, mainnet in production.
- No email. A wallet user has no address unless they add one later, so tokens carry no
email. - Android. In Chrome on Android the page also lists Wallet app on this phone, which signs in with the person's wallet app through Mobile Wallet Adapter. Chrome first asks whether the page may connect to apps on the phone; the page explains the question, and once it's allowed the person taps again to open their wallet app. Inside another app's browser, wallet apps can't be reached, so the page says to open it in Chrome. Browser extensions and in-wallet browsers work as everywhere.
- Going straight to it. Add
synq_method=walletto the authorization request to open the sign-in page at the wallet list.
From your own page
The brand's own apps can sign a wallet in on their own page, with no Synq page on the way. The issuer still writes the request, and checks the signature as it does on its own page.
- Ask the issuer for a request from your page:
POST https://<issuer>/siws/noncewith{"client_id": "<your app>"}as JSON. Only the brand's own apps can ask, and only from a page on the origin of one of the app's redirect URIs (the issuer answers that origin through CORS). The request names your page's host as its domain, so the wallet checks it against your page. - Have the wallet sign it with
solana:signIn, passing the request as it came. - Push the result. Send a pushed authorization request with
prompt=loginandsynq_siws: base64url of{"address": "…", "signature": "<standard base64>", "nonce": "<the request's nonce>"}. - Send the browser to the issuer with the
request_uri. It comes straight back to your redirect URI with a code, or witherror=access_deniedwhen the signature isn't the wallet's, the request expired or was already used, or it was another app's.
synq_siws is refused outside a pushed request, without prompt=login, and from any app that isn't the brand's own.
From a native app
A phone app signs a wallet in the same way, with a wallet app on the phone through Mobile Wallet Adapter: @synqauth/solana-mobile/react-native's mobileWalletSignInUrl asks for the request, has the wallet app sign it, pushes it, and gives you the URL to open in the system browser, which comes straight back to the app.
This needs an https identity the app claims: register an https redirect URI on a domain you own, and prove the app owns it, with an App Link (/.well-known/assetlinks.json) on Android and a universal link (apple-app-site-association) on iOS. Pass that origin as appOrigin. Wallet apps show it and check it against the app, the Sign In With Solana message names its domain, and the issuer answers a wallet request only from one of the app's redirect origins.
An app whose only redirect URI is a scheme of its own, such as com.example.app:/callback, can sign people in through the browser, the wallet step included, but not with a wallet from its own screen: a scheme proves nothing about who owns the app, so mobileWalletSignInUrl refuses it with invalid_options before asking anyone.
A person can hold several wallets: they list them and name one, or make it primary through the account API, and add another by linking.
A brand can also let people in only while their wallets hold enough of a token: see token gates.