Identity Forwarding
Delegierte Authentifizierung zu Third-Party-Systemen mit meinGPT JWT
JWT Identity Forwarding
Mit JWT Identity Forwarding gibt meinGPT einen signierten JSON Web Token an Dritt-Systeme weiter, damit diese den aktuellen Nutzer und die Organisation sicher identifizieren können.
Dieses Muster wird in zwei Bereichen genutzt:
- Custom MCP Server — Token im HTTP-Header
X-meinGPT-JWT - Custom AI Apps (iframe) — Token im URL-Hash-Fragment
Achtung
JWT-Tokens werden nur für Nutzer mit der Rolle Admin oder Mitglied ausgestellt. Viewer erhalten keine Tokens.
Token-Details
| Eigenschaft | Wert |
|---|---|
| Algorithmus | RS256 (RSA + SHA-256) |
| Gültigkeit | 1 Stunde |
| Header | Enthält kid (Key-ID) für Key-Rotation |
| Issuer | Die Origin Deiner meinGPT-Instanz (z. B. https://app.meingpt.com) |
Claims-Referenz
| Claim | Typ | Beschreibung |
|---|---|---|
iss | string | Issuer — die Plattform-Origin (z. B. https://app.meingpt.com) |
sub | string | Subject — die User-ID |
aud | string | Audience — die Organization-ID |
exp | number | Ablaufzeit (Unix-Timestamp, 1 Stunde ab Ausstellung) |
iat | number | Ausstellungszeitpunkt (Unix-Timestamp) |
jti | string | Eindeutige Token-ID (UUID, ändert sich bei jeder Ausstellung) |
email | string | E-Mail-Adresse des Nutzers |
username | string | Anzeigename des Nutzers |
organizationName | string | Name der Organisation |
role | string | "admin" oder "member" |
teams | array | Teams des Nutzers — jeder Eintrag hat id und name |
Beispiel-Payload:
{
"iss": "https://app.meingpt.com",
"sub": "clx1234567890",
"aud": "clx0987654321",
"exp": 1719504000,
"iat": 1719500400,
"jti": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"email": "max@example.com",
"username": "Max Mustermann",
"organizationName": "Acme Corp",
"role": "admin",
"teams": [
{ "id": "clxteam001", "name": "Engineering" }
]
}Verifikation über JWKS
Öffentliche Schlüssel werden pro Organisation bereitgestellt:
https://app.meingpt.com/api/custom-apps/v1/jwks/{organizationId}
import { createRemoteJWKSet, jwtVerify } from 'jose';
const JWKS = createRemoteJWKSet(
new URL('https://app.meingpt.com/api/custom-apps/v1/jwks/<organizationId>')
);
async function verifyMeinGptJwt(token: string) {
const { payload } = await jwtVerify(token, JWKS, {
issuer: 'https://app.meingpt.com',
audience: '<organizationId>',
});
console.log('User:', payload.email);
console.log('Role:', payload.role);
return payload;
}Transport: Custom MCP Server
Wenn JWT Identity Forwarding für einen MCP-Server aktiviert ist, enthält jeder Request:
X-meinGPT-JWT: eyJhbGciOiJSUzI1NiIs...Tokens werden innerhalb einer Chat-Session gecacht und 30 Sekunden vor Ablauf automatisch erneuert. Dein Server muss keine neuen Tokens anfragen — jeder MCP-Call kommt mit einem gültigen Token an.
So aktivierst Du es
Assistenten-Einstellungen öffnen
Navigiere zur Konfiguration Deines Assistenten und öffne den Bereich Tools.
Custom MCP Server hinzufügen oder bearbeiten
Füge einen neuen Custom MCP Server hinzu oder bearbeite einen bestehenden.
JWT-Authentifizierung aktivieren
Schalte JWT Authentication ein. Der Hinweistext bestätigt: „Sends a signed meinGPT JWT in header X-meinGPT-JWT."
Token auf Deinem Server lesen
Extrahiere den Header und verifiziere ihn:
// Express-Middleware-Beispiel
import { createRemoteJWKSet, jwtVerify } from 'jose';
const JWKS = createRemoteJWKSet(
new URL('https://app.meingpt.com/api/custom-apps/v1/jwks/<organizationId>')
);
app.use(async (req, res, next) => {
const token = req.headers['x-meingpt-jwt'];
if (!token) return res.status(401).json({ error: 'Missing JWT' });
try {
const { payload } = await jwtVerify(token, JWKS, {
issuer: 'https://app.meingpt.com',
audience: '<organizationId>',
});
req.user = payload;
next();
} catch {
res.status(401).json({ error: 'Invalid token' });
}
});Custom-Header mit JWT-Platzhalter
Alternativ zum Schalter kannst Du den Platzhalter {{MEINGPT_JWT}} in jedem Custom-Header-Wert verwenden. Das ist nützlich, wenn Dein Server den Token in einem anderen Header erwartet (z. B. Authorization: Bearer {{MEINGPT_JWT}}). Der Platzhalter wird zur Laufzeit durch den signierten JWT ersetzt.
Transport: Custom AI Apps (iframe)
Für eingebettete AI Apps wird der Token beim initialen Laden im URL-Hash-Fragment übergeben und per postMessage erneuert.
Initialer Token
Wenn meinGPT Deine App im iframe lädt, sieht die URL so aus:
https://deine-app.example.com/path#token=eyJhbGciOiJSUzI1NiIs...
So extrahierst Du ihn im Frontend:
function getInitialToken() {
const params = new URLSearchParams(window.location.hash.slice(1));
return params.get('token');
}Token-Refresh per postMessage
Tokens laufen nach 1 Stunde ab. Deine App kann jederzeit per postMessage einen neuen Token anfragen:
1. Neuen Token anfragen — sende an das Parent-Fenster:
window.parent.postMessage({ type: 'MEINGPT_TOKEN_REFRESH' }, '*');2. Auf die Antwort lauschen:
window.addEventListener('message', (event) => {
// Origin validieren
if (event.origin !== 'https://app.meingpt.com') return;
if (event.data.type === 'MEINGPT_TOKEN_RESPONSE') {
// Erfolg — neuen Token speichern
const { token, expiresAt } = event.data;
setToken(token);
scheduleRefresh(new Date(expiresAt));
}
if (event.data.type === 'MEINGPT_TOKEN_ERROR') {
// Token-Refresh fehlgeschlagen
console.error('Token refresh failed:', event.data.error);
}
});Nachrichtentypen:
| Nachricht | Richtung | Felder | Beschreibung |
|---|---|---|---|
MEINGPT_TOKEN_REFRESH | App → meinGPT | — | Neuen Token anfragen |
MEINGPT_TOKEN_RESPONSE | meinGPT → App | token, expiresAt | Neuer signierter JWT + Ablaufzeitpunkt |
MEINGPT_TOKEN_ERROR | meinGPT → App | error | Fehlermeldung als String |
Hinweis
meinGPT validiert die postMessage-Origin gegen Deine konfigurierte Embed-URL. Nachrichten von unbekannten Origins werden ignoriert.
Vollständiges Lifecycle-Beispiel
let currentToken = null;
let refreshTimer = null;
// 1. Initialen Token aus dem URL-Hash lesen
currentToken = new URLSearchParams(window.location.hash.slice(1)).get('token');
// 2. Refresh planen (z. B. 5 Minuten vor Ablauf)
function scheduleRefresh(expiresAt) {
clearTimeout(refreshTimer);
const ms = new Date(expiresAt).getTime() - Date.now() - 5 * 60 * 1000;
if (ms > 0) {
refreshTimer = setTimeout(requestRefresh, ms);
}
}
// 3. Refresh per postMessage anfragen
function requestRefresh() {
window.parent.postMessage({ type: 'MEINGPT_TOKEN_REFRESH' }, '*');
}
// 4. Antwort verarbeiten
window.addEventListener('message', (event) => {
if (event.origin !== 'https://app.meingpt.com') return;
if (event.data.type === 'MEINGPT_TOKEN_RESPONSE') {
currentToken = event.data.token;
scheduleRefresh(event.data.expiresAt);
}
});Sicherheitshinweise
Achtung
Verifiziere immer die JWT-Signatur über den JWKS-Endpunkt. Vertraue dem Token-Payload niemals ohne kryptografische Prüfung.
- Signatur verifizieren — nutze den JWKS-Endpunkt, dekodiere nicht einfach nur den Payload
expprüfen — lehne abgelaufene Tokens abaudvalidieren — stelle sicher, dass die Audience mit Deiner erwarteten Organization-ID übereinstimmt- HTTPS verwenden — Dein Endpunkt muss TLS nutzen, um den Token bei der Übertragung zu schützen
- Tokens nicht loggen — JWTs enthalten personenbezogene Daten (E-Mail, Name); vermeide es, sie in Anwendungslogs zu schreiben
- iframe-Apps:
event.originvalidieren — akzeptierepostMessage-Events nur von der Origin Deiner meinGPT-Instanz