---
title: "Identity Forwarding"
description: "Delegierte Authentifizierung zu Third-Party-Systemen mit meinGPT JWT"
canonical_url: "https://meingpt.com/docs/integrations/jwt-identity-forwarding"
language: de
---

# Identity Forwarding

## 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:

```json
{
  "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}
```

### Node.js (jose)

```typescript

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;
}
```

### Python (PyJWT)

```python

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:

```javascript
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:

```javascript
window.parent.postMessage({ type: 'MEINGPT_TOKEN_REFRESH' }, '*');
```

**2. Auf die Antwort lauschen:**

```javascript
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

```javascript
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
- **`exp` prüfen** — lehne abgelaufene Tokens ab
- **`aud` validieren** — 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.origin` validieren** — akzeptiere `postMessage`-Events nur von der Origin Deiner meinGPT-Instanz

## Weiterführend

- [Custom MCP Server](/docs/integrations/custom-mcp-server)
- [Security & Authentication Proxy](/docs/integrations/custom-ai-apps/security-auth-proxy)
