add codex skill

This commit is contained in:
RubenRWU
2026-05-06 15:27:00 +02:00
parent 723248dde5
commit 522740bc9e
3 changed files with 255 additions and 0 deletions

View File

@@ -0,0 +1,171 @@
---
name: onyva-login
description: Integriert den zentralen Onyva Dev Login (OIDC/SSO) in ein bestehendes Projekt. Verwende diesen Skill, wenn der Nutzer Onyva Login, OIDC, SSO, Auth-Integration oder /onyva-login in einem Projekt umsetzen will.
---
Integriere den zentralen Onyva Dev Login (OIDC/SSO unter `https://login.onyva.dev`) in das aktuelle Projekt.
## Workflow
1. Analysiere zuerst das Projekt.
Prüfe Framework, Routing, bestehende Auth-Logik, Session-Handling und Env-Konfiguration, bevor du Code änderst.
2. Kläre fehlende Eingaben nur dann, wenn sie nicht aus dem Repo ableitbar sind.
Du brauchst:
- `OIDC_CLIENT_ID`
- `OIDC_CLIENT_SECRET`
- `OIDC_REDIRECT_URI`
- `OIDC_LOGOUT_REDIRECT_URI`
- welche Routen geschützt sein sollen und welche öffentlich bleiben
3. Implementiere die Integration passend zum vorhandenen Stack.
4. Aktualisiere `.env.example` oder die äquivalente Konfiguration.
## Technische Vorgaben
### Auth-Server
- Issuer / Basis-URL: `https://login.onyva.dev`
- Discovery: `https://login.onyva.dev/.well-known/openid-configuration`
| Endpunkt | Methode | Zweck |
|---|---|---|
| `/oauth/authorize` | GET | Login starten |
| `/oauth/token` | POST | Code gegen Tokens tauschen |
| `/oauth/userinfo` | GET | Nutzerinfos per Bearer Token |
| `/oauth/jwks.json` | GET | Public Keys (RS256) |
| `/logout` | GET | Zentrales Logout |
### Login starten
Generiere `state` (mindestens 16 Zeichen, zufällig) und `code_verifier` (PKCE), speichere beide serverseitig in der Session. Dann Weiterleitung zu:
```text
GET https://login.onyva.dev/oauth/authorize
?response_type=code
&client_id={OIDC_CLIENT_ID}
&redirect_uri={OIDC_REDIRECT_URI}
&scope=openid profile email
&state={state}
&code_challenge={BASE64URL(SHA256(code_verifier))}
&code_challenge_method=S256
```
`state` ist Pflicht. Ohne `state` kommt im Callback kein `state` zurück.
### Callback verarbeiten
```python
def callback(request):
if request.params.get("state") != session.pop("oauth_state", None):
return error("State mismatch")
if "auth_disabled" in request.params:
session["user"] = {"auth_disabled": True}
return redirect("/")
resp = http_post("https://login.onyva.dev/oauth/token", data={
"grant_type": "authorization_code",
"code": request.params["code"],
"redirect_uri": OIDC_REDIRECT_URI,
"client_id": OIDC_CLIENT_ID,
"client_secret": OIDC_CLIENT_SECRET,
"code_verifier": session.pop("pkce_verifier"),
})
tokens = resp.json()
claims = decode_jwt(tokens["id_token"])
session["user"] = {
"sub": claims["sub"],
"email": claims["email"],
"name": claims["name"],
"user_type": claims["user_type"],
"app_roles": claims["app_roles"],
}
return redirect("/")
```
Nach erfolgreichem Callback nie auf `/auth/*` zurückleiten. `return_to` immer auf `/` oder eine echte App-Seite normalisieren.
### JWT Claims
```json
{
"sub": "user:42",
"email": "nutzer@onyva.de",
"name": "Max Mustermann",
"user_type": "employee",
"app_roles": ["admin"],
"iss": "https://login.onyva.dev",
"aud": "mein-client-id",
"exp": 1700000000
}
```
### Logout
```python
def logout(request):
session.clear()
return redirect(
f"https://login.onyva.dev/logout"
f"?post_logout_redirect_uri={urllib.parse.quote(OIDC_LOGOUT_REDIRECT_URI)}"
)
```
`post_logout_redirect_uri` muss absolut sein (`https://...`).
### Auth-Mode-Verhalten
| auth_mode | Auth-Server-Verhalten | Client-Verhalten |
|---|---|---|
| `required` | 403 wenn keine Mitgliedschaft | Fehlermeldung anzeigen |
| `optional` | Code für jeden angemeldeten Nutzer; `app_roles` ggf. leer | App entscheidet selbst |
| `disabled` | Sofort zurück mit `?auth_disabled=1` | Kein Login-Dialog, alle Funktionen offen |
### Entwicklungsmodus
```python
def require_auth(request):
if not AUTH_ENABLED:
return {
"sub": "user:0",
"email": "dev@local",
"name": "Dev",
"user_type": "employee",
"app_roles": ["admin"],
}
```
### Env-Variablen
```env
OIDC_ISSUER=https://login.onyva.dev
OIDC_CLIENT_ID=
OIDC_CLIENT_SECRET=
OIDC_REDIRECT_URI=
OIDC_LOGOUT_REDIRECT_URI=
AUTH_ENABLED=true
```
## Fallstricke
- `state` immer mitsenden und validieren
- Redirect URI muss exakt mit dem Eintrag im Admin-Panel übereinstimmen
- Token-Endpunkt mit `application/x-www-form-urlencoded`, nicht JSON
- Session-Middleware korrekt aktivieren
- Öffentliche Routen explizit vom Auth Guard ausnehmen
- Kein Redirect zurück auf `/auth/*`
## Checkliste
- [ ] Env-Variablen ergänzt und `.env.example` aktualisiert
- [ ] Redirect URI im Admin-Panel eingetragen
- [ ] Login-Route mit `state` und PKCE gebaut
- [ ] Callback validiert `state` und tauscht Code gegen Tokens
- [ ] Claims landen in der Session
- [ ] Logout löscht lokale Session und ruft zentrales Logout auf
- [ ] Geschützte und öffentliche Routen sauber getrennt
- [ ] `AUTH_ENABLED=false` für lokale Entwicklung berücksichtigt
- [ ] `auth_disabled=1` Fall behandelt