Files
oidc-test/CLAUDE.md
T
2026-06-17 17:17:18 +02:00

3.1 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

Flask 2.x Proof-of-Concept to demonstrate fine-grained, dynamic RBAC and multi-tenancy using Zitadel as OIDC IdP. Authentication is fully delegated to Zitadel; authorization and project assignments are handled locally via SQLite.

The full specification is in claude-context.md.

Commands

Local Development (venv)

python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
cp .env.example .env   # then fill in Zitadel credentials
flask db-init          # initialize SQLite schema
flask seed-db          # seed mock data (Firma Müller, 3 projects, sample notes)
flask run

Docker / Production

docker compose up --build   # builds image from Dockerfile, reads .env
docker compose down

Database CLI commands

flask seed-db   # wipes and re-seeds the SQLite database with test fixtures

Architecture

Flat backend, rich local authorization:

  • Zitadel (external) — handles login, issues OIDC tokens carrying the user's global role claim (Admin, Mitarbeiter, or Kunde).
  • app/auth.py — Authlib OIDC client; extracts sub, role claims, and token scopes from the IdP response; logs token payload to stdout in development.
  • app/models.py — SQLAlchemy models for the local relational layer:
    • User (keyed on Zitadel sub)
    • Client (top-level company, e.g. "Firma Müller")
    • Project (belongs to one Client)
    • ProjectMitarbeiterMapping (N:M: employees ↔ projects)
    • ProjectKundenMapping (N:M: external users ↔ projects)
    • Note (timestamped text entry tied to a Project)
  • app/routes.py — all routing guards live here; unauthorized access always redirects to login_error.html (never raises HTTP errors).
  • app/config.py — reads .env; follows 12-Factor style.
  • app/database.py — SQLAlchemy engine/session setup.

Role-Based Access (RBAC) Logic

Role Access
Admin Full visibility; all clients, projects, users; global export
Mitarbeiter Only projects linked via ProjectMitarbeiterMapping
Kunde Only projects linked via ProjectKundenMapping for their client

Routing guard pattern: Every protected route checks (1) Zitadel role from session, (2) local DB mapping for the requested resource. Any mismatch → redirect to /error (renders login_error.html). The error page has a JS back-button to support test flows.

Environment Variables

See .env.example:

FLASK_APP=app
FLASK_ENV=development
SECRET_KEY=...
ZITADEL_CLIENT_ID=...
ZITADEL_CLIENT_SECRET=...
ZITADEL_DISCOVERY_URL=https://<instance>.zitadel.cloud/.well-known/openid-configuration
DATABASE_URL=sqlite:///app.db

Docker Notes

  • Dockerfile uses python:3.11-slim, runs app via gunicorn.
  • docker-compose.yml builds from source (no pre-built images), mounts a volume for the SQLite file, and reads .env directly.
  • Setting pull_policy: always (or equivalent) in the compose file ensures a base-image update triggers a rebuild.