Files
onyva-login-skill/codex/skills/onyva-login/SKILL.md
2026-05-06 15:27:00 +02:00

5.0 KiB

name, description
name description
onyva-login 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:

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

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

{
  "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

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

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

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