Session Tokens


When you sign in to the SolRouter web interface at solrouter.io, your browser does not use an API key. Instead, the web UI authenticates using short-lived JWT session tokens stored in secure HttpOnly cookies. This page explains how that system works, why it is designed the way it is, and how it differs from API keys.


What is a session token?

A session token is a JSON Web Token (JWT) — a signed, self-contained piece of data that proves your identity to the SolRouter backend. The token is issued by the server when you sign in and is attached automatically to every subsequent request your browser makes to the API.

Session tokens are completely separate from API keys (sr_...). They serve a different purpose and are managed differently:

Session tokenAPI key
Used byWeb browser (UI)Your application code
Stored inHttpOnly cookieEnvironment variable / secrets manager
Created bySigning in to the dashboardAccount → API Keys → Create key
Lifetime15 minutes (access) / 30 days (refresh)Until revoked
Readable by JSNoYes (you must keep it secret)
Revoked bySigning outClicking Revoke in the dashboard

Signing in

The SolRouter dashboard supports four sign-in methods:

Email and password

Enter the email address and password you registered with. On success, the server sets two HttpOnly cookies in your browser and redirects you to the dashboard.

Google

Click Continue with Google to go through the standard Google OAuth 2.0 flow. You are redirected back to SolRouter with your session established — no password required.

GitHub

Click Continue with GitHub to authorise the SolRouter OAuth application. GitHub asks you to confirm the requested permissions (read-only access to your public profile and email address), then redirects you back with your session established.

Phantom wallet

Click Continue with Phantom to authenticate using your Solana wallet. SolRouter presents a sign message request in the Phantom browser extension. Signing the message proves ownership of the wallet address without revealing your private key. Your wallet address is used as the unique identifier for your account.

No transaction is submitted to the blockchain. The authentication is entirely off-chain via a signed message.


HttpOnly cookies — why not localStorage?

After a successful sign-in, SolRouter sets two cookies on your browser:

Set-Cookie: sr_access_token=<JWT>; HttpOnly; Secure; SameSite=Strict; Path=/
Set-Cookie: sr_refresh_token=<JWT>; HttpOnly; Secure; SameSite=Strict; Path=/

HttpOnly means the cookie cannot be read by JavaScript running on the page — not by your own code, not by any third-party script, not by browser extensions that inject scripts. document.cookie will not include it.

This directly prevents the most common web authentication attack: Cross-Site Scripting (XSS). If an attacker manages to inject malicious JavaScript into a page that stores its auth token in localStorage, they can steal the token with a single line of code (localStorage.getItem('token')). A token stored in an HttpOnly cookie is completely invisible to JavaScript, so the same attack gains nothing.

Storage locationReadable by JSXSS risk
localStorage✅ YesHigh — any injected script can steal it
sessionStorage✅ YesHigh — same as localStorage
In-memory variable✅ Yes (within the tab)Medium — lost on refresh
HttpOnly cookie❌ NoVery low — JS cannot access it

The Secure flag ensures the cookie is only ever sent over HTTPS. The SameSite=Strict flag prevents the cookie from being sent with cross-site requests, mitigating Cross-Site Request Forgery (CSRF).


Access tokens and refresh tokens

SolRouter issues two tokens on sign-in, each with a different lifetime and purpose.

Access token (15-minute lifetime)

The access token is a short-lived JWT that the SolRouter API accepts as proof of your identity. It is included in every request the web UI makes to the API while you are signed in.

Because it expires after 15 minutes, the damage from a hypothetically leaked access token is limited to a narrow window. After expiry, the token is rejected with a 401 Unauthorized response.

The access token payload contains:

{
  "sub": "user_01HXYZ...",
  "email": "you@example.com",
  "iat": 1716000000,
  "exp": 1716000900
}
FieldMeaning
subYour unique user ID
emailYour account email address
iatIssued-at timestamp (Unix seconds)
expExpiry timestamp — exactly 15 minutes after iat

Refresh token (30-day lifetime)

The refresh token is a long-lived JWT used solely to obtain a new access token without requiring you to sign in again. It is never sent to general API endpoints — it is sent only to the dedicated /auth/refresh endpoint.

When your access token expires, the SolRouter web UI automatically calls /auth/refresh with the refresh token. If the refresh token is still valid, the server issues a fresh access token and a new refresh token (rolling refresh), and both cookies are updated transparently.

This means you stay signed in for up to 30 days of continuous use without ever entering your password again. After 30 days of inactivity, the refresh token expires and you are redirected to the sign-in page.


Automatic token refresh

The refresh process is entirely transparent. You will never see an error or a sign-in prompt simply because your access token expired mid-session. Here is what happens under the hood:

Browser → GET /api/dashboard          (access token attached via cookie)
Server  → 401 Unauthorized            (access token has expired)
Browser → POST /auth/refresh          (refresh token attached via cookie)
Server  → 200 OK + new cookies        (new access token + new refresh token set)
Browser → GET /api/dashboard (retry)  (new access token attached)
Server  → 200 OK                      (request succeeds)

The web UI intercepts the 401 response, performs the refresh in the background, and retries the original request. From your perspective, the dashboard simply continues working.

If the refresh token itself has expired (after 30 days of inactivity), the refresh call returns 401 and you are redirected to the sign-in page.


Session tokens vs API keys — do not confuse them

A common point of confusion is that session tokens and API keys both authenticate requests to SolRouter. They are fundamentally different:

Session tokens are for the web UI only. They are managed automatically by the browser and you never need to copy, store, or handle them manually. You cannot use a session token to make API requests from your own code.

API keys are for your applications. They are long-lived, manually managed, and must be kept secret. They are what you pass as Authorization: Bearer sr_... from your server-side code or scripts.

Trying to use a session token as an API key, or an API key as a session token, will not work. The two systems are separate.


Signing out

Clicking Sign out in the dashboard sends a request to the /auth/signout endpoint. The server:

  1. Invalidates the refresh token server-side — even if someone had stolen the cookie value, the token is now permanently rejected
  2. Clears both cookies by setting them to empty values with an expiry in the past

After sign-out, no further API requests can be made with the previous tokens, even if they have not yet reached their expiry time. Session invalidation is immediate.

If you suspect your session has been compromised (for example, you left a shared computer signed in), sign out from any device to invalidate all tokens associated with that session. For account-wide session revocation, changing your password also invalidates all active refresh tokens.


Security properties summary

PropertyValue
Token formatSigned JWT (HS256)
Access token lifetime15 minutes
Refresh token lifetime30 days (rolling)
Cookie flagsHttpOnly, Secure, SameSite=Strict
Accessible to JavaScriptNo
XSS protectionYes — HttpOnly prevents JS access
CSRF protectionYes — SameSite=Strict blocks cross-site requests
Revocable before expiryYes — sign out invalidates server-side
Transmitted over HTTPNo — Secure flag enforces HTTPS only

Next steps

  • API Keys — creating, naming, and managing programmatic API keys
  • Security Best Practices — environment variables, secrets managers, and leak response
  • Quickstart — make your first API request with an sr_ key