keycloak init

This commit is contained in:
MaKarin
2026-03-21 16:00:27 +03:00
parent 33521016d3
commit 8d6875f4b0
50 changed files with 2242 additions and 252 deletions

60
AUTH_RUNTIME.md Normal file
View File

@@ -0,0 +1,60 @@
# Runtime Keycloak Auth
This repository now uses Keycloak-based authentication for the runtime application only (`client/` and `server/`).
## Required environment variables
### Frontend (`client/.env`)
- `VITE_API_URL` (example: `http://localhost:3000`)
- `VITE_KEYCLOAK_URL` (example: `https://sso.greact.ru`)
- `VITE_KEYCLOAK_REALM` (example: `toir`)
- `VITE_KEYCLOAK_CLIENT_ID` (example: `toir-frontend`)
The frontend fails fast at startup if any required auth/env variable is missing.
### Backend (`server/.env`)
- `PORT` (example: `3000`)
- `DATABASE_URL`
- `CORS_ALLOWED_ORIGINS` (comma-separated list)
- `KEYCLOAK_ISSUER_URL` (example: `https://sso.greact.ru/realms/toir`)
- `KEYCLOAK_AUDIENCE` (example: `toir-backend`)
- `KEYCLOAK_JWKS_URL` (optional)
Backend validates required env vars at startup and fails fast if missing.
## Frontend auth flow
- The SPA initializes Keycloak before rendering.
- Authentication is redirect-based Keycloak login only (no custom username/password form).
- Authorization Code + PKCE (`S256`) is used.
- Access token is attached to every API request via `Authorization: Bearer <token>`.
- `checkError` behavior:
- `401`: force re-authentication.
- `403`: keep session and surface access denied to React Admin.
- Token refresh is concurrency-safe: parallel requests share one in-flight refresh operation.
## Backend JWT validation and RBAC
- JWTs are verified against:
- issuer: `KEYCLOAK_ISSUER_URL`
- audience: `KEYCLOAK_AUDIENCE`
- JWKS resolution priority:
1. explicit `KEYCLOAK_JWKS_URL`
2. OIDC discovery (`/.well-known/openid-configuration`)
3. fallback `${issuer}/protocol/openid-connect/certs`
- RBAC source is only `realm_access.roles`.
Role policy applied to CRUD endpoints:
- `GET`: `viewer`, `editor`, `admin`
- `POST`, `PATCH` (and `PUT` if added): `editor`, `admin`
- `DELETE`: `admin`
Public route:
- `GET /health`
All other existing API routes require authentication.