105 lines
5.0 KiB
Markdown
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`.
|