Wallet challenge flow
- Request a challenge through
POST /v1/auth/challengeusing the exact shared input schema. - Present the returned domain- and chain-bound message to the connected wallet.
- Submit the signature and challenge through
POST /v1/auth/verify. - The server validates the signature and the challenge’s purpose, expiry, and single-use status, then returns the appropriate account/session result.
Sessions
The service stores hashed, expiring session credentials and uses an HTTP-only cookie. Browser requests to protected routes must use the intended session transport. The public read SDK deliberately omits credentials and cannot replace the authenticated application client. State-changing requests enforce the configured allowed origin and CSRF requirements. Do not disable those protections to make a third-party integration work; design a supported integration boundary instead.Sensitive account changes
Destructive or sensitive actions can require a fresh, single-use signed confirmation. A normal sign-in challenge and a confirmation challenge serve different purposes. Expired or reused confirmation produces a reauthentication requirement rather than silently allowing the action. Account deletion and session revocation affect application access. They cannot erase immutable public chain history.Server-side protections
The API validates both inputs and successful outputs with shared Zod schemas. Account resources are ownership-scoped. Private delivery checks the buyer and sale state, including refund revocation. Image uploads are sanitized and re-encoded rather than served as arbitrary untrusted content. The testnet gas service has separate funding limits and durable transaction tracking. Its purpose is MON gas assistance; it never supplies merchant commission rewards or signs a user’s purchases.Integrator guidance
- Keep private signing keys, provider credentials, session cookies, and delivery URLs out of logs and public repositories.
- Do not put secrets into frontend
NEXT_PUBLIC_*variables. - Treat a signed wallet challenge as authentication, not a payment.
- Check chain and contract identity before showing transaction-specific data.
- Respect the returned retryability and request IDs; use bounded retries.
Exact challenge and session behavior
A sign-in challenge expires after five minutes and is consumed once. Its message includes the configured web domain, URI, chain, nonce, issue time, and expiration.accountKind accepts wallet, passkey, or phrase; purpose distinguishes signIn, link, and confirm.
For confirmation, the current session signer must match the challenge address and the action name must be supplied. A successful confirmation creates another five-minute, single-use token bound to the session and action. A linked-wallet challenge is bound to its owning account.
The current session lifetime is 24 hours. Production uses the secure HTTP-only __Host-spoke_session cookie with SameSite=Lax and path /; development uses spoke_session. The response returns a separate CSRF token. The raw session and confirmation credentials are not stored in the database: their hashes are.
Both sign-in endpoints require the configured origin even though their route classification is public. Public in that context means no existing session is required, not that any website may establish a session.
Example challenge body
message, signature, and method; it does not take a password or seed phrase. See the exact method schemas.
A successful verification can return a session, an action confirmation, or a new-account recovery result with no session, depending on the purpose and account kind. Validate the union instead of assuming every HTTP 200 contains a CSRF token.