Skip to main content
Auth UI Boilerplate uses a modern, secure JWT/JWKS authentication approach that eliminates the need for shared secrets between your frontend and backend services.

How It Works

The authentication flow follows these steps:
1

User Authentication

Users sign in via email/password or OAuth (Google) through Better Auth. Better Auth manages the session securely.
2

JWT Token Issuance

When your frontend needs to call your backend API, it requests a JWT from Better Auth via the /api/auth/token endpoint. The JWT is signed with the server’s private key (Ed25519 by default).
3

Token Transmission

The frontend includes the JWT in the Authorization: Bearer <token> header when making API requests to your backend.
4

Token Verification

Your backend verifies the JWT signature by fetching the public keys from Better Auth’s JWKS endpoint at /api/auth/jwks. No shared secrets needed.

Why JWKS?

JWKS (JSON Web Key Set) provides several advantages over traditional shared secret approaches:

No Shared Secrets

Your backend never needs to know the private signing key. It only uses public keys to verify signatures.

Key Rotation

Better Auth can rotate signing keys without requiring backend redeployment. New keys are automatically discovered via the JWKS endpoint.

Multiple Backends

Multiple backend services can all verify tokens using the same JWKS endpoint without sharing credentials.

Industry Standard

JWKS is a widely adopted standard (RFC 7517) with robust library support across all major programming languages.

Authentication Flow Diagram

Token Structure

Better Auth issues JWTs with the following standard claims:
ClaimDescriptionExample
subUser ID (subject)"abc123def456"
issIssuer (Better Auth URL)"http://localhost:3000"
audAudience (Better Auth URL)"http://localhost:3000"
expExpiration timestamp1234567890
iatIssued at timestamp1234567800
emailUser’s email address"[email protected]"
nameUser’s display name"John Doe"
JWTs are short-lived by default (typically 1 hour). The frontend automatically refreshes tokens when they’re close to expiration (within 10 seconds).

API Client Integration

The boilerplate includes two ready-to-use API clients with automatic JWT injection:
import apiClient from "@/lib/api-client"

// JWT is automatically included in the Authorization header
const response = await apiClient.verifyAuth()
Both clients:
  • Cache JWTs and refresh them automatically when close to expiration
  • Add a 10-second buffer to prevent using tokens about to expire
  • Include the token in the Authorization: Bearer <token> header
  • Handle token errors gracefully

Backend Implementation Guides

Choose your backend language to see complete integration examples:

Go

JWT verification with github.com/lestrrat-go/jwx

Python

Flask middleware with PyJWT and PyJWKClient

Express

Express middleware with jose library

Security Best Practices

JWTs are bearer tokens. Anyone who intercepts a token can impersonate the user until it expires. Follow these security practices:

Always Use HTTPS in Production

JWTs transmitted over HTTP can be intercepted. Always use TLS/HTTPS for both your frontend and backend in production.

Verify Signatures, Don’t Just Decode

Never trust the JWT payload without verifying the signature against the JWKS public keys. Simply decoding a JWT doesn’t prove authenticity.
import { decodeJwt } from "jose"

// WRONG: Anyone can create a JWT with fake claims
const payload = decodeJwt(token)
const userId = payload.sub // ⚠️ Not verified!

Validate Token Claims

Always validate the iss (issuer), aud (audience), and exp (expiration) claims:
const { payload } = await jwtVerify(token, JWKS, {
  issuer: process.env.BETTER_AUTH_URL,
  audience: process.env.BETTER_AUTH_URL,
  // exp is automatically validated by jwtVerify
})

Respect Token Expiration

Always check the exp claim and reject expired tokens. Most JWT libraries do this automatically during verification.

Cache JWKS Keys Appropriately

Fetching JWKS keys on every request is inefficient. Cache them with a reasonable TTL (e.g., 1 hour), but be prepared to refresh if verification fails with an unknown key ID.

Next Steps

JWKS Endpoint Details

Learn how the JWKS endpoint works and how to implement key rotation

Build docs developers (and LLMs) love