Files
member-console/docs/identity-provider-setup.md
T

105 lines
5.0 KiB
Markdown

---
title: "Identity Provider Setup"
audience: [admin, developer]
summary: "Configure an OIDC identity provider (Keycloak-focused) so the console can authenticate users and assign the operator role."
---
# Identity Provider Setup
This guide covers configuring your OIDC identity provider to work with the member console. The examples use Keycloak but the concepts apply to any OIDC-compliant provider.
## Prerequisites
- An OIDC identity provider with a client configured for Authorization Code + PKCE flow
- The client ID and secret configured in `mc-config.yaml` (or equivalent flags)
## Standard OIDC Claims
The member console reads the following standard claims from the **ID token**:
| Claim | Used for |
|-------|----------|
| `sub` | Unique user identifier (OIDC subject) |
| `email` | User's primary email |
| `email_verified` | Whether the email is verified |
| `name` | Display name |
| `preferred_username` | Username (used for org slug derivation) |
On first login, the member console auto-provisions a person, organization, and workspace from these claims.
## Role-Based Access: Operator Role
The member console uses a single application-level role to gate access to the operator panel:
- **Role name:** `operator-member`
- **Where it's checked:** `internal/server/operator.go` and `operator_partials.go`
### How roles are extracted
The member console extracts roles from the **access token** by decoding the JWT payload and reading every claim location an identity provider might use to carry roles, rather than trusting only one:
1. `roles` (top-level array)
2. `groups` (top-level array)
3. `realm_access.roles` (Keycloak realm roles)
4. `resource_access.<client-id>.roles` (Keycloak client-scoped roles, read only for this app's configured client ID; roles belonging to other clients are never included)
The member console reads all four locations and merges their roles into one deduplicated list: a role that appears in more than one location is kept once, at the position where it first appears (the locations are read in the order listed above, and within a location, in the order the claim lists them). Because every location is read, a deployment can put `operator-member` in whichever claim its identity provider produces and the member console still recognizes it.
### Keycloak setup
There are two ways to make the `operator-member` role visible in the access token:
#### Option A: Client role with a protocol mapper (recommended)
1. Go to **Clients > member-console > Roles**
2. Create a role named `operator-member`
3. Assign it to the desired user(s) under **Users > (user) > Role Mappings > member-console**
4. Ensure there is a protocol mapper that emits client roles into a top-level `roles` claim in the access token:
- **Mapper type:** User Client Role
- **Client ID:** `member-console`
- **Token Claim Name:** `roles`
- **Claim JSON Type:** String
- **Multivalued:** On
- **Add to access token:** On
This is the approach used by the test stack's Keycloak seed (`test/seed/keycloak/seed-keycloak.sh`).
#### Option B: Realm role
1. Go to **Realm Roles**
2. Create a role named `operator-member`
3. Assign it to the desired user(s)
4. The role will appear in `realm_access.roles` in the access token by default
This is simpler but mixes application roles with realm-level roles.
### Other identity providers
For providers other than Keycloak, ensure that the access token includes `operator-member` in one of the four checked claim locations (`roles`, `groups`, `realm_access.roles`, or `resource_access.<client-id>.roles`). Most providers support custom claims or group mappings that can achieve this.
## Temporal Authorization
Temporal requires its own role setup for JWT-based authorization. See [Temporal Authorization Setup](temporal-authorization-setup.md) for the full Temporal permissions configuration.
## Test Environment
The test stack's Keycloak seed (`test/seed/keycloak/seed-keycloak.sh`) pre-configures:
- A `member-console` client with the `operator-member` client role defined
- The admin user mapped to the `operator-member` role
- Protocol mappers that emit roles into the access token
To use the test environment:
```bash
cd test
docker compose up -d
member-console start
```
Login with `admin` / `admin` at `http://localhost:8081`.
> **Run app OIDC on a dedicated realm, not Keycloak's `master` admin realm.** The member-facing "Identity and Access" link opens Keycloak's account console; on the `master` admin realm that console errors (*"Something went wrong"*) because the minted token carries no `aud: account` claim. The test stack therefore creates and runs on a dedicated `test` realm, where the account console works out of the box — do the same in production. See `status/issues.md`.
> **Note:** The first `member-console start` after a fresh `docker compose up -d` used to fail with a Temporal auth error. This is fixed — compose now gates Temporal on its database and Keycloak being healthy, and member-console retries the initial Temporal connection. See `status/issues.md`.