Skip to content

Example application ​

The repository includes a SQLite authentication backend and a shared React client. It demonstrates account registration, login, access-token renewal, session management, and password changes/reset.

Run locally ​

Requires Node.js 24+ and Yarn 4. From the repository root:

sh
yarn install
yarn workspace session-tether-example-sqlite dev

In another terminal:

sh
yarn workspace session-tether-example-sqlite dev:client

Open http://127.0.0.1:5173. The API listens on http://127.0.0.1:3000, and SQLite data persists in examples/sqlite/data/sessions.sqlite.

The backend command builds and watches the compiled server. After editing TypeScript, rebuild the example or restart dev. If SQLite's native binding is missing, run yarn rebuild sqlite3 and inspect its output.

Authentication flow ​

  • Registration signs in immediately; login creates a named refresh session.
  • HttpOnly, SameSite=Lax cookies carry the access JWT and opaque refresh token. A separate HttpOnly preference cookie preserves Remember me across rotations.
  • Access JWTs use jose and last five minutes. Refresh sessions have a 30-day server-side lifetime.
  • /api/auth/me verifies the JWT locally. If it needs renewal, the backend validates and rotates the refresh token and issues a new JWT with the same family identifier.
  • POST /api/auth/refresh performs the same renewal explicitly.
CredentialCookie nameLifetime
Refresh tokensession_tetherBrowser session, or 30-day cookie with Remember me; each successful rotation resets server-side expiry to 30 days
Access JWTsession_tether_accessBrowser-session cookie; JWT validity is five minutes
Remember me preferencesession_tether_remember30 days when enabled; cleared otherwise

JWTs use HS256 with issuer session-tether-sqlite-example and audience session-tether-example-api. Their sid claim holds the stable refresh-family identifier. These are example conventions, not settings imposed by the library.

Rotation and grace

Successful renewal replaces the refresh cookie and gives the successor a new 30-day lifetime. A consumed-token retry within the default 30-second grace window renews only the access JWT, leaving the refresh cookie untouched so it cannot overwrite the successful rotation's successor. Reuse at or after the grace boundary revokes the family and clears cookies. A lost successor cannot be recovered from its hash.

Sessions and passwords ​

Active-session listing uses the adapter's filtering query. Individual revocation checks ownership. Signing out other devices preserves the current session. Password changes revoke existing sessions and create a replacement for the current browser; password resets revoke all sessions.

Forgot password returns an empty success response for valid email input. Existing accounts receive a development reset link printed to the backend terminal. These links expire after 15 minutes and work once. This example does not deliver email.

Configuration ​

VariableDefaultPurpose
PORT3000Backend port
DATABASE_PATHexamples/sqlite/data/sessions.sqlitePersistent database
CLIENT_ORIGINhttp://127.0.0.1:5173Mutation origin checks and reset links
JWT_SECRETRandom key per server processAccess JWT signing key

A supplied JWT_SECRET must contain at least 32 bytes. A stable key keeps JWTs verifiable across restarts. HTTPS origins enable Secure cookies. The server binds to 127.0.0.1.

Set BACKEND_URL or VITE_EXAMPLE_NAME in examples/client/.env.local to change the client proxy target or example label, then restart Vite.

Verification ​

sh
yarn workspace session-tether-example-sqlite typecheck
yarn workspace session-tether-example-sqlite test
yarn workspace session-tether-example-client test

This is a local development example. A deployed application needs its own production credential transport, abuse controls, reset delivery, and concurrency design.

Built for explicit authentication boundaries. Powered by VitePress.