keycloak init
This commit is contained in:
120
auth/backend-auth-rules.md
Normal file
120
auth/backend-auth-rules.md
Normal file
@@ -0,0 +1,120 @@
|
||||
# Backend Auth Rules
|
||||
|
||||
This document defines mandatory backend authentication and authorization behavior for generated applications.
|
||||
|
||||
---
|
||||
|
||||
# Generated Backend Auth Surface
|
||||
|
||||
The generator must create explicit auth infrastructure in the generated NestJS backend.
|
||||
|
||||
At minimum generate:
|
||||
|
||||
- `server/src/auth/auth.module.ts`
|
||||
- JWT auth guard
|
||||
- roles guard
|
||||
- `@Public()`
|
||||
- `@Roles()`
|
||||
- typed authenticated principal interface
|
||||
- typed environment validation in `server/src/config/`
|
||||
|
||||
The generator must not describe backend auth as an external manual integration step.
|
||||
|
||||
---
|
||||
|
||||
# Standards-Based JWT Verification
|
||||
|
||||
The generated backend must validate JWTs against Keycloak using standards-based libraries.
|
||||
|
||||
Rules:
|
||||
|
||||
1. Verify **issuer**
|
||||
2. Verify **audience**
|
||||
3. Verify signature via **JWKS**
|
||||
4. Do **not** use deprecated Keycloak-specific Node adapters such as `keycloak-connect`
|
||||
|
||||
The default library rule for this repository is:
|
||||
|
||||
- **`jose`** for JWT and JWKS verification
|
||||
|
||||
---
|
||||
|
||||
# JWT Verification Contract
|
||||
|
||||
The generated backend must verify tokens with:
|
||||
|
||||
- `KEYCLOAK_ISSUER_URL`
|
||||
- `KEYCLOAK_AUDIENCE`
|
||||
|
||||
JWKS resolution priority must be exactly:
|
||||
|
||||
1. explicit `KEYCLOAK_JWKS_URL`
|
||||
2. OIDC discovery
|
||||
3. fallback `${issuer}/protocol/openid-connect/certs`
|
||||
|
||||
The generator must encode this priority explicitly.
|
||||
|
||||
---
|
||||
|
||||
# Role Extraction
|
||||
|
||||
Authorization roles must be extracted **only** from:
|
||||
|
||||
- `realm_access.roles`
|
||||
|
||||
The generator must not mix in:
|
||||
|
||||
- resource roles
|
||||
- custom frontend-only permissions
|
||||
- undocumented claim fallbacks
|
||||
|
||||
`realm_access.roles` is the single RBAC source for this repository.
|
||||
|
||||
---
|
||||
|
||||
# Default RBAC Policy
|
||||
|
||||
Apply these RBAC defaults to generated CRUD controllers:
|
||||
|
||||
- `GET`: `viewer`, `editor`, `admin`
|
||||
- `POST`: `editor`, `admin`
|
||||
- `PATCH`: `editor`, `admin`
|
||||
- `PUT`: `editor`, `admin`
|
||||
- `DELETE`: `admin`
|
||||
|
||||
`GET /health` must remain public and must use the generated `@Public()` mechanism.
|
||||
|
||||
All other generated CRUD routes must be protected by default.
|
||||
|
||||
---
|
||||
|
||||
# Typed Principal
|
||||
|
||||
The generated backend must attach a typed authenticated principal to the request context.
|
||||
|
||||
At minimum, the generated principal type must be able to represent:
|
||||
|
||||
- `sub`
|
||||
- user identity fields when present
|
||||
- `roles`
|
||||
- raw claims payload
|
||||
|
||||
This principal type is required so guards, controllers, and tests share one consistent contract.
|
||||
|
||||
---
|
||||
|
||||
# Backend Environment Contract
|
||||
|
||||
The generated backend env contract must include:
|
||||
|
||||
- `PORT`
|
||||
- `DATABASE_URL`
|
||||
- `CORS_ALLOWED_ORIGINS`
|
||||
- `KEYCLOAK_ISSUER_URL`
|
||||
- `KEYCLOAK_AUDIENCE`
|
||||
- `KEYCLOAK_JWKS_URL` (optional)
|
||||
|
||||
The generated backend config must **fail fast** if required auth variables are missing.
|
||||
|
||||
The generated backend must not silently fall back to production auth settings in code.
|
||||
|
||||
134
auth/frontend-auth-rules.md
Normal file
134
auth/frontend-auth-rules.md
Normal file
@@ -0,0 +1,134 @@
|
||||
# Frontend Auth Rules
|
||||
|
||||
This document defines mandatory frontend authentication behavior for generated applications.
|
||||
|
||||
---
|
||||
|
||||
# Generated Files
|
||||
|
||||
The generator must create at minimum:
|
||||
|
||||
- `client/src/config/env.ts`
|
||||
- `client/src/auth/keycloak.ts`
|
||||
- `client/src/auth/authProvider.ts`
|
||||
- `client/src/App.tsx`
|
||||
- `client/src/main.tsx`
|
||||
- `client/src/dataProvider.ts`
|
||||
- `client/.env.example`
|
||||
|
||||
`App.tsx`, `main.tsx`, and `dataProvider.ts` must be generated in an auth-aware form. Auth must not be bolted on later.
|
||||
|
||||
---
|
||||
|
||||
# Login Model
|
||||
|
||||
The generated frontend must use:
|
||||
|
||||
- **Keycloak JS**
|
||||
- **Authorization Code Flow + PKCE**
|
||||
- **PKCE method `S256`**
|
||||
- **redirect-based login only**
|
||||
|
||||
The generator must **not** create a custom in-app username/password login form.
|
||||
|
||||
The generated SPA must initialize Keycloak **before rendering** the application. The app must not operate anonymously once auth is enabled.
|
||||
|
||||
---
|
||||
|
||||
# React Admin Integration
|
||||
|
||||
The generated frontend must use a React Admin **`authProvider`** and connect it at the `Admin` root.
|
||||
|
||||
Rules:
|
||||
|
||||
1. `authProvider` is mandatory.
|
||||
2. The generated `Admin` root must enforce authenticated operation.
|
||||
3. Auth bootstrap must happen before rendering `Admin`.
|
||||
|
||||
The generated frontend must not rely on anonymous access with later lazy auth attachment.
|
||||
|
||||
---
|
||||
|
||||
# Shared Request Seam
|
||||
|
||||
The generated frontend must use the shared request seam in `client/src/dataProvider.ts` as the single place where access tokens are attached.
|
||||
|
||||
Rules:
|
||||
|
||||
1. All backend requests must carry `Authorization: Bearer <access_token>`.
|
||||
2. This must cover all React Admin calls, including:
|
||||
- list
|
||||
- get one
|
||||
- get many
|
||||
- get many reference
|
||||
- create
|
||||
- update
|
||||
- delete
|
||||
3. Reference/resource lookups must flow through the same authenticated request seam.
|
||||
|
||||
The generator must not scatter token attachment across resource components.
|
||||
|
||||
---
|
||||
|
||||
# Error Semantics
|
||||
|
||||
The generated `authProvider.checkError` must distinguish authentication failures from authorization failures:
|
||||
|
||||
- `401` -> force logout / re-authentication
|
||||
- `403` -> do **not** re-authenticate; surface access denied / permission error to React Admin
|
||||
|
||||
The generator must not treat `401` and `403` as equivalent.
|
||||
|
||||
---
|
||||
|
||||
# Token Refresh
|
||||
|
||||
The generated frontend must refresh tokens before protected API calls when needed.
|
||||
|
||||
Refresh behavior must be **concurrency-safe**:
|
||||
|
||||
- use one shared in-flight refresh operation
|
||||
- parallel requests must wait for the same refresh promise
|
||||
- do not trigger multiple parallel refresh requests for the same expiry window
|
||||
|
||||
The generator must explicitly describe or implement the shared in-flight refresh pattern.
|
||||
|
||||
---
|
||||
|
||||
# Browser Storage Rules
|
||||
|
||||
The generated frontend must **not** store access tokens or refresh tokens in:
|
||||
|
||||
- `localStorage`
|
||||
- `sessionStorage`
|
||||
|
||||
In-memory handling via Keycloak JS behavior is the default rule for this repository.
|
||||
|
||||
---
|
||||
|
||||
# Frontend Environment Contract
|
||||
|
||||
The generated frontend env contract must include:
|
||||
|
||||
- `VITE_API_URL`
|
||||
- `VITE_KEYCLOAK_URL`
|
||||
- `VITE_KEYCLOAK_REALM`
|
||||
- `VITE_KEYCLOAK_CLIENT_ID`
|
||||
|
||||
The generated frontend config module must **fail fast** if required auth variables are missing.
|
||||
|
||||
The generated frontend must not silently fall back to production auth settings in code.
|
||||
|
||||
---
|
||||
|
||||
# Default Values for Examples
|
||||
|
||||
`client/.env.example` must use these repository defaults as examples:
|
||||
|
||||
```env
|
||||
VITE_API_URL=http://localhost:3000
|
||||
VITE_KEYCLOAK_URL=https://sso.greact.ru
|
||||
VITE_KEYCLOAK_REALM=toir
|
||||
VITE_KEYCLOAK_CLIENT_ID=toir-frontend
|
||||
```
|
||||
|
||||
89
auth/keycloak-architecture.md
Normal file
89
auth/keycloak-architecture.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# Keycloak Architecture
|
||||
|
||||
This repository generates a fullstack CRUD application with **default Keycloak authentication and authorization**. Authentication is not an optional add-on and must not be described as a manual post-generation task.
|
||||
|
||||
---
|
||||
|
||||
# Default Auth Model
|
||||
|
||||
The generated application must use this runtime topology:
|
||||
|
||||
- **Frontend:** SPA served by Vite + React Admin
|
||||
- **Backend:** NestJS API
|
||||
- **Auth transport:** `Authorization: Bearer <access_token>`
|
||||
- **Identity provider:** external Keycloak server
|
||||
|
||||
The generated application must **not** use:
|
||||
|
||||
- a BFF layer
|
||||
- cookie/session authentication
|
||||
- a custom in-app username/password login form
|
||||
|
||||
The generated application must use **redirect-based Keycloak login** only.
|
||||
|
||||
---
|
||||
|
||||
# Auth Is Part of Default Generation
|
||||
|
||||
The generator must produce:
|
||||
|
||||
- authenticated frontend bootstrap and request flow
|
||||
- authenticated backend bootstrap and request guards
|
||||
- auth-aware env examples
|
||||
- auth-aware validation rules
|
||||
- a root-level Keycloak realm import artifact that describes the Keycloak realm/client bootstrap
|
||||
|
||||
Repository defaults may use names such as `toir`, `toir-frontend`, `toir-backend`, and `toir-realm.json`, but future generations must parameterize realm name, client IDs, production URLs, and artifact filename from the generated project or explicit auth configuration.
|
||||
|
||||
The generated application must not require a separate prompt step such as "now add auth manually".
|
||||
|
||||
---
|
||||
|
||||
# Public and Protected Routes
|
||||
|
||||
The generated backend must keep:
|
||||
|
||||
- `GET /health` — public
|
||||
|
||||
All generated CRUD routes must be protected by default.
|
||||
|
||||
Authorization must be role-based and must use **only** Keycloak realm roles from `realm_access.roles`.
|
||||
|
||||
---
|
||||
|
||||
# Default Role Policy
|
||||
|
||||
Apply these RBAC defaults to generated CRUD controllers:
|
||||
|
||||
- `GET` list/detail: `viewer`, `editor`, `admin`
|
||||
- `POST`, `PATCH`, `PUT`: `editor`, `admin`
|
||||
- `DELETE`: `admin`
|
||||
|
||||
The frontend may use roles for display and permission awareness, but the backend remains the enforcement point.
|
||||
|
||||
---
|
||||
|
||||
# Token Contract
|
||||
|
||||
Generated auth context must guarantee that access tokens used by the SPA and API reliably contain:
|
||||
|
||||
- `sub`
|
||||
- `aud`
|
||||
- `realm_access.roles`
|
||||
|
||||
The frontend client and backend audience/client must be documented explicitly. The generator must not rely on undocumented Keycloak defaults for these claims.
|
||||
|
||||
---
|
||||
|
||||
# Runtime Boundaries
|
||||
|
||||
The repository's local runtime topology remains unchanged:
|
||||
|
||||
- `docker-compose.yml` provisions PostgreSQL only
|
||||
- Keycloak remains external to this repo's Docker runtime
|
||||
|
||||
The generator must therefore produce:
|
||||
|
||||
- runtime documentation for importing/configuring the generated realm import artifact
|
||||
- env contracts for frontend and backend
|
||||
- validation rules that assume an external but reachable Keycloak server
|
||||
152
auth/keycloak-realm-template-rules.md
Normal file
152
auth/keycloak-realm-template-rules.md
Normal file
@@ -0,0 +1,152 @@
|
||||
# Keycloak Realm Template Rules
|
||||
|
||||
This document defines the required Keycloak realm/bootstrap artifact that the generator must produce.
|
||||
|
||||
---
|
||||
|
||||
# Required Artifact
|
||||
|
||||
The generator must create a root-level Keycloak import artifact:
|
||||
|
||||
- project-specific realm import artifact
|
||||
- repository default example filename: `toir-realm.json`
|
||||
|
||||
This artifact is part of the normal generated result and must be documented in the runtime bootstrap flow.
|
||||
|
||||
The generator must parameterize at minimum:
|
||||
|
||||
- realm name
|
||||
- frontend SPA client ID
|
||||
- backend audience/resource client ID
|
||||
- production frontend URLs
|
||||
- realm-artifact filename
|
||||
|
||||
Repository defaults may use `toir`, `toir-frontend`, `toir-backend`, `toir-realm.json`, and `https://toir-frontend.greact.ru` as examples, but those names must not be treated as universal requirements for all future generated applications.
|
||||
|
||||
---
|
||||
|
||||
# Strategy Choice
|
||||
|
||||
This repository uses the **robust bootstrap strategy** by default.
|
||||
|
||||
That means the generated realm/client setup must be:
|
||||
|
||||
- self-contained
|
||||
- reproducible after import
|
||||
- explicit about audience delivery
|
||||
- explicit about role delivery
|
||||
- explicit about required claims
|
||||
|
||||
The generator must **not** rely on built-in client scopes magically existing and attaching correctly after realm import.
|
||||
|
||||
---
|
||||
|
||||
# Required Realm Structure
|
||||
|
||||
The generated realm import artifact must define:
|
||||
|
||||
- realm name derived from generated project auth config
|
||||
- realm roles:
|
||||
- `admin`
|
||||
- `editor`
|
||||
- `viewer`
|
||||
- frontend SPA client ID derived from generated project auth config
|
||||
- backend audience/resource client ID derived from generated project auth config
|
||||
- dedicated audience client scope for audience delivery
|
||||
- repository default example: `api-audience`
|
||||
|
||||
The audience client scope must explicitly add the generated backend audience/client ID to SPA access tokens.
|
||||
|
||||
---
|
||||
|
||||
# Required Frontend Client Rules
|
||||
|
||||
The generated SPA client must be configured as a public SPA client with:
|
||||
|
||||
- `publicClient: true`
|
||||
- `standardFlowEnabled: true`
|
||||
- `implicitFlowEnabled: false`
|
||||
- `directAccessGrantsEnabled: false`
|
||||
- `serviceAccountsEnabled: false`
|
||||
- `pkce.code.challenge.method: S256`
|
||||
|
||||
Default rule:
|
||||
|
||||
- keep `fullScopeAllowed: true`
|
||||
|
||||
Reason:
|
||||
|
||||
- this repository uses realm-role RBAC
|
||||
- earlier failures came from fragile or implicit scope behavior
|
||||
- the robust default is explicit audience delivery plus explicit claim mappers, not a partially documented scoped-role setup
|
||||
|
||||
If a future prompt chooses `fullScopeAllowed: false`, it must also fully document role scope mappings and validation rules. The generator must not switch to that strategy silently.
|
||||
|
||||
---
|
||||
|
||||
# Required Claim Delivery
|
||||
|
||||
The generated realm/client configuration must reliably produce access tokens containing:
|
||||
|
||||
- `sub`
|
||||
- `aud`
|
||||
- `realm_access.roles`
|
||||
|
||||
The generator must explicitly address claim delivery and must not leave it implicit.
|
||||
|
||||
The generated realm import artifact must therefore define explicit protocol mappers for:
|
||||
|
||||
- `sub`
|
||||
- user identity claims needed by the frontend
|
||||
- `realm_access.roles`
|
||||
|
||||
The generator must not assume these claims will appear through undeclared built-in scopes.
|
||||
|
||||
Post-generation validation must fail if the generated realm contract leaves `sub`, `aud`, or `realm_access.roles` implicit instead of explicitly delivered.
|
||||
|
||||
---
|
||||
|
||||
# Required Role Delivery
|
||||
|
||||
The generated realm/client configuration must explicitly deliver realm roles into the access token.
|
||||
|
||||
Rules:
|
||||
|
||||
1. Role delivery must be configured intentionally.
|
||||
2. `realm_access.roles` must be present in the access token after import.
|
||||
3. The generator must validate that realm role delivery is part of the generated realm artifact.
|
||||
|
||||
---
|
||||
|
||||
# Redirect URIs and Web Origins
|
||||
|
||||
The generated realm template guidance must document local and production frontend URLs derived from the generated project configuration.
|
||||
|
||||
Repository default production examples may include:
|
||||
|
||||
- `http://localhost:5173`
|
||||
- `https://toir-frontend.greact.ru`
|
||||
|
||||
The generated SPA client must include matching redirect URIs and web origins for the generated local and production frontend URLs. These values must be explicit in the generated realm artifact or in a generated artifact template with explicit placeholders and validation instructions.
|
||||
|
||||
---
|
||||
|
||||
# Anti-Regression Rule
|
||||
|
||||
The earlier broken realm-template behavior must not be reproduced.
|
||||
|
||||
The generator context must explicitly prevent:
|
||||
|
||||
- missing audience in SPA access tokens
|
||||
- missing `sub`
|
||||
- missing `realm_access.roles`
|
||||
- realm imports that depend on undeclared built-in scopes being present
|
||||
- ambiguous role-delivery behavior
|
||||
|
||||
The generated realm/bootstrap guidance must be self-contained enough that another engineer can import the artifact and predict the access-token shape without relying on hidden Keycloak defaults.
|
||||
|
||||
The generator must guarantee through the generated realm artifact plus post-generation validation that imported access tokens reliably contain:
|
||||
|
||||
- `sub`
|
||||
- `aud`
|
||||
- `realm_access.roles`
|
||||
Reference in New Issue
Block a user