# Keycloak and generic OIDC

Both self-hosted products can verify tokens issued by an operator-owned OIDC
provider. Runku does not become the identity provider.

## Authentication versus authorization

OIDC configuration answers “is this token valid?”. Product stores answer “what
may this identity do?”. Do not encode roles, table policy, model access or
consumer quotas in bootstrap YAML.

## Generic configuration

```yaml
# MCP Forge token verification against your Keycloak realm.
auth:
  # Reject unauthenticated requests.
  enabled: true
  oidc:
    # Public realm URL used for discovery and signature verification.
    issuer: https://id.example.com/realms/company
    # Audience required in tokens presented to MCP endpoints.
    audience: runku
    # Public PKCE client used by the MCP portal.
    portal_client_id: runku-portal
```

For AI Gateway, use the AI-specific audience and client:

```yaml
# AI Gateway token verification uses its own audience and portal client.
auth:
  # Reject unauthenticated administrative and gateway requests as applicable.
  enabled: true
  oidc:
    # Same organization realm, independently validated by AI Gateway.
    issuer: https://id.example.com/realms/company
    # Audience dedicated to AI Gateway tokens.
    audience: runku-ai
    # Public PKCE client dedicated to the AI Gateway portal.
    portal_client_id: runku-ai-portal
```

## Keycloak client setup

1. Create a realm or use an existing company realm.
2. Create a public client for the portal with Authorization Code + PKCE.
3. Add the production portal origin and redirect URI.
4. Create or configure the API audience expected by Runku.
5. Add an audience protocol mapper if the access token does not contain the
   configured `aud` value.
6. Validate discovery and token claims before testing the portal.

Typical redirect origins include the product `/portal/` URL and CLI loopback
callbacks when using AI login.

## Validate discovery

```bash
runku-ai auth oidc check \
  --issuer https://id.example.com/realms/company
```

Then inspect a real JWT and confirm:

- `iss` exactly matches the configured issuer;
- `aud` contains the configured audience;
- `exp` and `nbf` are valid;
- the identity claim used for matching is present.

## MCP Forge identity binding

Create an OIDC identity in the MCP Forge admin store and bind it to a role.
The verified claim, such as `preferred_username`, must match the stored identity.
The role can only narrow connector policy; it cannot reveal a masked column.

## AI Gateway portal and CLI

OIDC authenticates administrators and can support personal consumer-key flows.
It does not replace `rk_ai_…` authentication for normal `/v1/*` client calls.

```bash
runku-ai login --url https://ai.example.com --sso
runku-ai whoami
runku-ai logout
```

## Common failures

| Symptom | Check |
|---|---|
| Discovery fails | Issuer URL, TLS trust and network access |
| Token rejected for audience | Keycloak audience mapper and YAML `audience` |
| Portal redirect loop | Exact origin/redirect registration and PKCE client type |
| User authenticates but has no MCP access | Stored OIDC identity and role binding |
| IDE receives an admin error | Use an `rk_ai_…` consumer key, not the portal token |
