# IdP setup: Google Workspace & Microsoft Entra ID

Runku (MCP `runku` and AI Gateway `runku-ai`) verify bearer JWTs via standard
OIDC discovery. Both products follow the same
`auth.oidc` YAML shape.

## Quick validation (no credentials required)

```bash
# Google Workspace
runku-ai auth oidc check --issuer https://accounts.google.com

# Microsoft Entra ID (replace TENANT_ID)
runku-ai auth oidc check --issuer https://login.microsoftonline.com/TENANT_ID/v2.0
```

Discovery must return `authorization_endpoint` and `token_endpoint`. If that
fails, the issuer URL is wrong (common Entra mistake: missing `/v2.0`).

## Google Workspace

Example configs:

- AI: `configs/config.ai.oidc-google.example.yaml`
- MCP: `configs/config.oidc-google.example.yaml`

Rules:

| Field | Value |
|-------|--------|
| `issuer` | `https://accounts.google.com` |
| `audience` | OAuth **Client ID** |
| `portal_client_id` | Same Client ID (public PKCE client) |
| Bearer token | **ID token** (auto via `prefer_id_token` for Google) |

Google access tokens are opaque — Runku cannot verify them as JWTs. Portals and
`runku-ai login` therefore send the `id_token` when discovery sets
`prefer_id_token: true`.

## Microsoft Entra ID

Example configs:

- AI: `configs/config.ai.oidc-entra.example.yaml`
- MCP: `configs/config.oidc-entra.example.yaml`

Rules:

| Field | Value |
|-------|--------|
| `issuer` | `https://login.microsoftonline.com/<tenant-id>/v2.0` |
| `audience` | API app ID / App ID URI (`api://…`) |
| `portal_client_id` | SPA / public client ID |
| Bearer token | **Access token** JWT (`prefer_id_token: false`) |

Expose an API scope and grant the SPA client access so the access token’s `aud`
matches `auth.oidc.audience`.

## CLI login (AI Gateway)

Point the CLI at a running gateway — discovery (`GET /auth/config`) decides
whether SSO and/or a consumer key (`rk_ai_…`) are available. **Never** use
`rk_admin_…` here (that is portal/admin only).

```bash
# Auto: asks SSO vs key when OIDC is configured; otherwise prompts for rk_ai_
runku-ai login --url http://localhost:8088

# Consumer key only
runku-ai login --url http://localhost:8088 --key rk_ai_...

# Force IdP redirect (requires auth.oidc on the gateway)
runku-ai login --url http://localhost:8088 --sso

runku-ai whoami
runku-ai logout
```

SSO path: browser PKCE → optional `POST /admin/v1/me/keys` → stores `rk_ai_…`
under `~/.config/runku/ai/credentials.json`.


## MCP portal SSO

Same discovery endpoint: `GET /auth/config`. MCP portal uses the same PKCE
flow; send the token type advertised by `prefer_id_token`.
