main
Authentik OIDC — React + Node
Demo stack showing the standard OIDC split:
| Layer | Token | Purpose |
|---|---|---|
| React frontend | ID Token | Login, user profile (sub, email, name) |
| Node API | Access Token | Authorization: Bearer on protected routes |
┌─────────────┐ OIDC (PKCE) ┌──────────────┐
│ React │ ◄──────────────────► │ Authentik │
│ (Vite) │ ID + Access tokens │ (Provider) │
└──────┬──────┘ └──────────────┘
│ Bearer access_token
▼
┌─────────────┐ JWKS verify JWT ┌──────────────┐
│ Express │ ◄────────────────── │ Authentik │
│ API :3001 │ │ JWKS │
└─────────────┘ └──────────────┘
Prerequisites
- Node.js 18+
- Running Authentik instance
1. Configure Authentik
- In Authentik Admin → Applications → Providers → Create → OAuth2/OpenID Provider.
- Set:
- Client type: Public (for SPA + PKCE)
- Redirect URIs:
http://localhost:5173 - Signing Key: your instance default
- Scopes:
openid,profile,email(defaults are fine)
- Create an Application and link it to this provider.
- Note:
- Client ID (slug or UUID from provider)
- Issuer / OpenID Configuration URL — typically
https://<your-authentik>/application/o/<slug>/
Copy issuer and client ID into env files (see below).
2. Environment files
cp frontend/.env.example frontend/.env
cp backend/.env.example backend/.env
Edit both files with your Authentik issuer URL and client ID.
OIDC_AUDIENCE on the backend should match the access token aud claim (usually the same client ID for Authentik).
3. Install and run
npm run install:all
# Terminal 1 — API
npm run dev:backend
# Terminal 2 — frontend
npm run dev:frontend
Open http://localhost:5173 → Sign in → after login you’ll see ID token claims and can call GET /api/me with the access token.
Project layout
frontend/ React + react-oidc-context (ID token for UI)
backend/ Express + jose JWKS validation (access token)
deploy/ Docker Compose (Authentik + app) for Ubuntu server
How it works
Frontend (react-oidc-context + PKCE):
- Redirects to Authentik for login
- Stores session in
localStorage - Reads ID token claims via
auth.user.profile - Sends access token as
Authorization: Bearer <token>to the API
Backend (jose):
- Fetches JWKS from
{OIDC_ISSUER}.well-known/jwks - Verifies JWT signature,
iss, and optionalaud - Exposes user info from access token claims on
/api/me
Troubleshooting
| Symptom | Check |
|---|---|
| Redirect URI mismatch | Authentik redirect URI must exactly match http://localhost:5173 |
| Invalid issuer | VITE_OIDC_AUTHORITY and OIDC_ISSUER must be identical (trailing slash) |
| 401 on API | OIDC_AUDIENCE must match token aud; token must be sent as Bearer |
| CORS errors | CORS_ORIGIN must match frontend URL |
Deploy on Ubuntu Server (Docker)
See deploy/README.md for Dockerfiles, docker compose, and Authentik on Ubuntu (e.g. Azure VM).
cd deploy
sudo ./install-ubuntu.sh
cp .env.example .env # edit SERVER_HOST, URLs
./start-authentik.sh
docker compose --env-file .env up -d --build
Production notes
- Use HTTPS redirect URIs
- Prefer httpOnly cookies or BFF pattern if you need to hide tokens from the browser
- Rotate signing keys in Authentik as documented
- Restrict CORS to your real frontend origin
Description
Languages
TypeScript
39.7%
JavaScript
20.3%
Shell
18.4%
CSS
16.6%
Dockerfile
3.4%
Other
1.6%