forked from Onyva/onyva-login-skill
add codex skill
This commit is contained in:
84
codex/README.md
Normal file
84
codex/README.md
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
# Codex-Version
|
||||||
|
|
||||||
|
Dieses Repo enthält unter [codex/skills/onyva-login/SKILL.md](/home/ruben/PycharmProjects/onyva-login-skill/codex/skills/onyva-login/SKILL.md) eine Codex-kompatible Version des bestehenden Claude-Skills.
|
||||||
|
|
||||||
|
## Lokale Nutzung in Codex
|
||||||
|
|
||||||
|
Lege den Skill lokal in deinem Codex-Home unter `skills/onyva-login/` ab, sodass dort eine `SKILL.md` liegt. Wenn du ihn aus diesem Repo kopieren willst:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p ~/.codex/skills/onyva-login
|
||||||
|
cp /home/ruben/PycharmProjects/onyva-login-skill/codex/skills/onyva-login/SKILL.md ~/.codex/skills/onyva-login/SKILL.md
|
||||||
|
```
|
||||||
|
|
||||||
|
Danach kannst du in Codex z. B. schreiben:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Nutze den Skill onyva-login und integriere den zentralen Login in dieses Projekt.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Upload nach Gitea mit Token
|
||||||
|
|
||||||
|
### 1. Persönlichen Access Token erzeugen
|
||||||
|
|
||||||
|
In Gitea:
|
||||||
|
|
||||||
|
1. Profilbild oben rechts öffnen
|
||||||
|
2. `Settings`
|
||||||
|
3. `Applications`
|
||||||
|
4. `Generate New Token`
|
||||||
|
5. Einen Namen vergeben, z. B. `codex-push`
|
||||||
|
6. Mindestens `repo`- bzw. Schreibrechte auf das Ziel-Repository geben
|
||||||
|
7. Token direkt kopieren, weil Gitea ihn danach meist nicht mehr vollständig zeigt
|
||||||
|
|
||||||
|
### 2. Remote mit Token setzen
|
||||||
|
|
||||||
|
Empfohlen ist ein temporärer Push per HTTPS mit Token:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git remote add gitea https://<USERNAME>:<TOKEN>@gitea.onyva.dev/<ORG>/<REPO>.git
|
||||||
|
```
|
||||||
|
|
||||||
|
Beispiel:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git remote add gitea https://ruben:DEIN_TOKEN@gitea.onyva.dev/Onyva/onyva-login-skill.git
|
||||||
|
```
|
||||||
|
|
||||||
|
Falls `gitea` schon existiert:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git remote set-url gitea https://<USERNAME>:<TOKEN>@gitea.onyva.dev/<ORG>/<REPO>.git
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Commit und Push
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add codex/README.md codex/skills/onyva-login/SKILL.md
|
||||||
|
git commit -m "Add Codex version of onyva-login skill"
|
||||||
|
git push gitea main
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Token nicht im Remote behalten
|
||||||
|
|
||||||
|
Nach dem Push den Remote wieder ohne Token setzen, damit der Token nicht in `git remote -v` sichtbar bleibt:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git remote set-url gitea https://gitea.onyva.dev/<ORG>/<REPO>.git
|
||||||
|
```
|
||||||
|
|
||||||
|
## Sicherere Alternative mit Credential Helper
|
||||||
|
|
||||||
|
Statt den Token in der URL zu speichern:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git remote add gitea https://gitea.onyva.dev/<ORG>/<REPO>.git
|
||||||
|
git push gitea main
|
||||||
|
```
|
||||||
|
|
||||||
|
Dann bei der Abfrage:
|
||||||
|
|
||||||
|
- Benutzername: dein Gitea-Username
|
||||||
|
- Passwort: dein persönlicher Access Token
|
||||||
|
|
||||||
|
Wenn dein System einen Credential Helper nutzt, wird der Token dort gespeichert statt in der Remote-URL.
|
||||||
171
codex/skills/onyva-login/SKILL.md
Normal file
171
codex/skills/onyva-login/SKILL.md
Normal 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
|
||||||
Reference in New Issue
Block a user