POST /v1/auth/link while signed in. Signing in later
with either wallet lands on the same user.
Endpoints
Challenge, login and link use the strict rate limit (10 a minute per IP). Refresh and logout allow
10 a minute per session.
Tokens and sessions
- A refresh token works once. Each refresh spends the current token and hands you the next.
Sending a spent token again within 30 seconds returns the same next pair (a retry after a lost
answer, or a second tab). After that, the relayer treats it as a stolen copy, ends the whole
session and answers
401 refresh-reused. - Refresh once, share the result. If several calls hit a
401at the same time, run one refresh and let every waiting call reuse it. Better, refresh a little before the access token’sexp, at a random point so clients signed in together do not refresh together. - Logout ends the refresh tokens at once. An access token already issued keeps working until its own 15 minutes run out, so delete it on your side.
Browser or server client
The relayer decides where the refresh token travels by looking at the request:- Browser (the request carries
OriginorSec-Fetch-Site, which page scripts cannot remove): the refresh token is set as an HttpOnly cookie,pb_refreshonPath=/v1/auth, and left out of the JSON body. Login, refresh and logout must come from the app’s origin with anX-Requested-Withheader, or they are refused with403 csrf-refused. Send them with credentials (credentials: "include"infetch,withCredentials: truein axios), or the browser drops the cookie. A browser refresh or logout sends{}as the body. - Server client (a bot, a script, an agent; Node’s
fetchcounts): both tokens come back in the body, and you send the refresh token in the body of refresh and logout. No cookie is read or set.
Get a challenge
POST /v1/auth/challenge
domain, uri, nonce and the checksummed address:
transaction exactly as it is, with networkPassphrase. Do not
add operations or change anything:
Log in
POST /v1/auth/login. Send it within 5 minutes of the challenge.
201:
- EVM. The message parses as SIWE with a checksummed address, its domain and URI match the challenge’s exactly, and the signature verifies as a plain wallet (EOA) signature. Smart-contract wallets (EIP-1271) cannot sign in. The nonce must belong to that address, be unused, and be no more than 60 seconds past its 5 minutes.
- Stellar. The transaction is this relayer’s challenge for this network, unchanged, and carries a signature by the account’s own master key. An account whose master key was replaced by other signers cannot sign in. Each signed challenge works once.
Refresh
POST /v1/auth/refresh
A server client sends its refresh token in the body:
{} with credentials; the cookie carries the token:
200. Store the new pair; the old refresh token is now spent. A browser gets access only
and a new pb_refresh cookie.
On any
401 here, sign the user out and start again at the challenge. A 429 or a 5xx is not a
sign-out: keep the tokens and try again later. A 401 also clears a browser’s cookie.
Log out
POST /v1/auth/logout. Takes the same body as refresh (a server client’s refresh token, or {}
from a browser). An expired refresh token still works, so you can log out after the access token
has run out.
Response 204 with no body. Every refresh token of that sign-in stops working; your other sign-ins
(another browser, another bot) are not touched. Logging out a session that has already ended still
answers 204. A browser’s cookie is cleared even when the token is refused.
Link the other wallet
POST /v1/auth/link, with your access token. Get a fresh challenge for the wallet you are adding,
sign it with that wallet, and send the same body as login. Instead of signing you in, the relayer
attaches the wallet to your user. No new tokens are issued.
201:
409 get a new challenge before you
try another wallet. There is no route to unlink or replace a wallet.
Linked smart accounts (a Stellar custody account, or an EVM custody account) are a separate thing;
see Accounts.
Who am I
GET /v1/user/me
403
No STELLAR wallet linked — connect and link the matching wallet to continue (or EVM) when you
lack the wallet kind they need.
JavaScript example
A server-side client signing in with an EVM key, calling a guarded route, refreshing and logging out. In a browser, addcredentials: "include" and an X-Requested-With header to the auth calls
and do not store the refresh token yourself: the pb_refresh cookie carries it.