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
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;
}import jwt
from jwt import PyJWKClient
JWKS_URL = "https://app.meingpt.com/api/custom-apps/v1/jwks/<organizationId>"
jwks_client = PyJWKClient(JWKS_URL)
def verify_meingpt_jwt(token: str) -> dict:
signing_key = jwks_client.get_signing_key_from_jwt(token)
payload = jwt.decode(
token,
signing_key.key,
algorithms=["RS256"],
issuer="https://app.meingpt.com",
audience="<organizationId>",
)
return payloadTransport: 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
Navigiere zur Konfiguration Deines Assistenten und öffne den Bereich Tools.
Füge einen neuen Custom MCP Server hinzu oder bearbeite einen bestehenden.
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 |
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
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