# Single Sign-On mit d4rkbot Der Bot ist Identity-Provider für die anderen D4RKST3R-Dienste (Kanban, Platform …). Statt in jeder App einen eigenen Discord-OAuth2-Flow zu bauen, fragst du beim Bot nach — und bekommst dabei gleich die **Discord-Rollen** des Users mitgeliefert. ## 1. App registrieren Setup → **API** → *Single Sign-On*: | Feld | Beispiel | Bedeutung | |---|---|---| | Kürzel | `kanban` | interner Slug, taucht in der URL auf | | Name | `Kanban-Board` | Anzeigename | | Rücksprung-URL | `https://kanban.d4rkst3r.de/` | erlaubte Ziele (mehrere kommagetrennt) | Beim Anlegen wird ein **Secret** angezeigt — einmalig, danach nie wieder. In der App als Umgebungsvariable hinterlegen (`SSO_SECRET`), niemals ins Repo. > Der Bot leitet ausschließlich auf Adressen zurück, die mit einer der hinterlegten > Rücksprung-URLs beginnen. Das verhindert, dass jemand den Login-Flow auf eine > fremde Seite umbiegt und den Token abgreift. ## 2. Ablauf ``` Nutzer klickt "Login" → https://bot.d4rkst3r.de/sso/authorize ?app=kanban &redirect=https://kanban.d4rkst3r.de/auth/callback ↓ (Bot prüft Session, ggf. erst Discord-Login) Zurück zu https://kanban.d4rkst3r.de/auth/callback?sso_token= ↓ (App tauscht den Token serverseitig ein) POST https://bot.d4rkst3r.de/sso/verify Authorization: Bearer { "token": "" } ``` Der Token ist **60 Sekunden** gültig und nur **einmal** einlösbar. Er selbst enthält keine Nutzerdaten — die gibt es erst beim Verify-Aufruf, der serverseitig passieren muss. ## 3. Antwort von `/sso/verify` ```json { "user": { "id": "123456789012345678", "username": "d4rkst3r", "displayName": "Alexander", "avatar": "https://cdn.discordapp.com/avatars/…", "joinedAt": "2026-02-01T12:00:00.000Z" }, "roles": [ { "id": "111…", "name": "Entwickler" }, { "id": "222…", "name": "Playtester" } ], "owner": false, "scopes": ["content", "server"], "app": "kanban" } ``` * `owner` — ist der Server-Owner (`ADMIN_DISCORD_ID`) * `scopes` — Team-Bereiche aus dem Bot (`['*']` beim Owner, sonst z. B. `['content']`) * `roles` — alle Discord-Rollen; damit kannst du in der App Rechte vergeben, ohne eine eigene Nutzerverwaltung zu pflegen ## 4. Beispiel (Node / Express) ```js const BOT = 'https://bot.d4rkst3r.de'; app.get('/login', (req, res) => { const redirect = `${process.env.PUBLIC_URL}/auth/callback`; res.redirect(`${BOT}/sso/authorize?app=kanban&redirect=${encodeURIComponent(redirect)}`); }); app.get('/auth/callback', async (req, res) => { const result = await fetch(`${BOT}/sso/verify`, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${process.env.SSO_SECRET}`, }, body: JSON.stringify({ token: req.query.sso_token }), }); if (!result.ok) return res.status(401).send('Login fehlgeschlagen'); const { user, roles, owner } = await result.json(); req.session.user = { id: user.id, name: user.displayName ?? user.username, avatar: user.avatar, // Rechte direkt aus den Discord-Rollen ableiten canEdit: owner || roles.some((r) => r.name === 'Entwickler'), }; res.redirect('/'); }); ``` ## 5. Hinweise * Der Verify-Aufruf muss **serverseitig** erfolgen — das Secret darf nie im Browser landen. * Nur Mitglieder des konfigurierten Discord-Servers können sich anmelden; alle anderen landen auf der Beitritts-Seite des Bots. * Rollen werden bei jedem Login frisch von Discord geholt. Wer eine Rolle verliert, verliert die Rechte beim nächsten Login — für sofortige Wirkung die Sitzung in der App kurz halten oder periodisch neu prüfen. * Wird eine App im Setup gelöscht, funktioniert ihr Login sofort nicht mehr.