lockAuthentication

Developer documentation: where to get current user data and how the server session differs from the wallet and Nado.

What counts as an authenticated user

After Sign-In with Ethereum (SIWE), the gateway sets an HTTP-only cookie named thornado_auth containing a JWT. The token stores only one identifier: the wallet's Ethereum address in lowercase, 0x + 40 hex characters.

There are no other profile fields such as name or email. The backend does not maintain a separate user table for this flow.

Three different sources of "who the user is"

Source
Where
What it gives

Server session (SIWE + JWT)

Cookie after POST /api/auth/verify

The address the user used to sign in. This is the only account for the API gateway.

Wallet (wagmi)

useAccount() and provider

The currently connected address in the extension; it can differ from the cookie address if the user switched accounts without signing in again.

Nado (trading)

SDK / linked signer

On-chain and engine-level logic; it does not replace server session verification for the THORNado HTTP API.

For features tied to being logged in to THORNado, rely on /api/auth/me or the session hook, and use the wallet for signatures and networks.

Client: where to get user data

useSession hook

File: client/src/hooks/useSession.js.

  • Performs GET /api/auth/me with credentials: 'include'.

  • A 401 response is treated as "no session" and React Query returns null.

  • Successful response:

address is always lowercase, matching the JWT on the server.

Usage example:

After sign-in or sign-out, the query cache should be refreshed. The project includes useInvalidateSession() for that purpose, which invalidates queryKey: ['session'].

Sign-in and sign-out in code

Action
Module
Note

Sign-in (nonce -> signature -> verify)

client/src/lib/siweAuth.js - signInWithThornado

After success, invalidate the session query.

Sign-out

same file - logoutSession

POST /api/auth/logout + credentials: 'include'.

SIWE domain on the client: VITE_SIWE_DOMAIN or window.location.host. It must match SIWE_DOMAIN on the gateway.

Aligning session address and wallet address

It is useful to compare session?.address with the wagmi address explicitly. If they do not match, show a warning or suggest another SIWE flow. Example logic: client/src/pages/Account.jsx (sessionAddr, walletAddr, sessionMatchesWallet).

HTTP API (gateway, Go)

Implementation: gateway/main.go.

In development, the frontend calls http://localhost:5173/api/...; Vite proxies /api to the gateway at http://127.0.0.1:3001 - see client/vite.config.js.

Authentication endpoints

Method
Path
Purpose

GET

/api/auth/nonce

Return a one-time nonce for SIWE. It lives for about 10 minutes.

POST

/api/auth/verify

Body: { "message": "<SIWE>", "signature": "0x..." } - verify the signature and issue a JWT in a cookie. Response: { "address": "0x..." }.

POST

/api/auth/logout

Clear the session cookie.

GET

/api/auth/me

Current user from cookie; 401 if not logged in. Response: { "address": "0x..." }.

Cookie: thornado_auth, HttpOnly, Path=/, SameSite=Lax, JWT lifetime by default is 24 hours.

New protected routes on the server

For endpoints that require the current user:

  1. Attach middleware requireAuth.

  2. Read the address from c.Get("address").

There is no other data in the JWT right now. If a profile is needed later, it must be expanded separately.

Gateway environment variables

Variable
Purpose

JWT_SECRET

JWT signing secret. Set it explicitly in production; otherwise the dev value from the code is used.

SIWE_DOMAIN

Domain in the SIWE message. It must match what the client sends. Default in code: localhost:5173.

SIWE_CHAIN_IDS or SIWE_CHAIN_ID

Allowed chain IDs for signing in, as a comma-separated list.

CORS_ORIGINS

Frontend origin for requests with cookies.

COOKIE_SECURE

1 or true sets the cookie Secure flag, which is required for HTTPS.

PORT

Gateway port. Defaults to 3001.

Short checklist for new code

  1. Read the user from the server via GET /api/auth/me or useSession(), always with credentials: 'include'.

  2. Do not confuse session.address with the wallet address without checking.

  3. Do not treat a wagmi connection as equivalent to a server session.

  4. For Nado operations, check the documentation and SDK separately. The server cookie is not injected into Nado requests automatically.

Was this helpful?