Sign in with your corporate IdP (mode B, brokered)¶
Mode B runs the bundled Keycloak as the OAuth issuer. Brokering points its
sign-in at your corporate IdP: users authenticate with their normal corporate
credentials — your SSO, your MFA, your session policies — and Keycloak
re-issues the token Précis-MCP verifies. Nothing changes on the Précis-MCP
side: PRECIS_AUTH_MODE=keycloak, the token check, and provisioning are
exactly as in Remote access. Everything on this page is
Keycloak configuration.
This is your path when:
- You want the public connectors (claude.ai / ChatGPT) and your IdP is Okta, Entra ID, or PingOne. Those connectors self-register via DCR and rely on RFC 8707 audience stamping — which these IdPs don't offer. The bundled Keycloak supplies both, while your IdP still authenticates every user. If you're on one of these IdPs, this is the standard setup, not a workaround — the decision matrix explains why.
- Your IdP is SAML-only. The Précis-MCP verifier speaks OIDC; Keycloak brokers SAML upstream.
- You want the sign-in stack self-contained, with your IdP as the source of credentials.
A brokered sign-in flows like this:
MCP client ── discovery ──► bundled Keycloak ── redirect ──► your IdP (login + MFA)
▲ │ creates/links the user record,
│ │ stamps precis_user_id + the /mcp audience
└────── token issued ◄───────┘
Step 1 — register a client for Keycloak in your IdP¶
To your IdP, Keycloak is just one more OIDC (or SAML) client:
- Pick the broker alias now (e.g.
corp) — it is part of the redirect URI and awkward to change later. - Register a confidential client with redirect URI
{PRECIS_BASE_URL}/auth/realms/precis/broker/corp/endpoint. - Note the client id and secret.
Per-IdP notes:
- Entra ID — an app registration, Web platform, the redirect URI above.
Use the tenant-specific v2 discovery URL
(
https://login.microsoftonline.com/<tenant-id>/v2.0/.well-known/openid-configuration), notcommon. - Okta — an OIDC Web Application; assign the users/groups who should reach Précis-MCP. The org authorization server is fine here — Keycloak only needs a standard login, so the custom-AS licensing question from the mode-C recipe doesn't arise.
- Ping — a standard OIDC client (PingFederate or PingOne both work as a brokered upstream).
- SAML — create the identity provider in Keycloak first (step 2); it then exposes SP metadata you import into your IdP.
Step 2 — add the identity provider to the realm¶
Open the Keycloak admin console with the bootstrap admin account. The
reference ingress blocks /auth/admin/ at the edge (see
hardening), so reach it over an SSH tunnel —
ssh -L 8080:127.0.0.1:8080 <host>, then http://localhost:8080/auth/admin/.
Select the precis realm, then Identity providers → Add provider:
- OpenID Connect v1.0 (or the built-in Microsoft provider, or SAML v2.0).
- Alias — the value from step 1's redirect URI.
- Discovery endpoint — your IdP's
.well-known/openid-configuration; Keycloak fills the endpoints from it. - Client ID / Client Secret — from step 1.
Sign-in now shows your IdP as a login option, and a user record is created in Keycloak automatically on each user's first brokered login. To send users straight to the corporate login (no local username/password form), set the Identity Provider Redirector in the browser authentication flow to default to your alias.
Step 3 — carry a stable identity into the token¶
The /mcp verifier reads the precis_user_id claim, which the bundled realm
fills from the Keycloak user attribute of the same name. CLI-provisioned
local users get the attribute set for them; brokered users need it filled from
the upstream identity. Two supported patterns:
A. Import the IdP's stable id, match on external_id (recommended).
On the identity provider, add a mapper: Attribute Importer, upstream claim
→ user attribute precis_user_id, sync mode FORCE (re-applied on every
login, so it can't drift). Choose the upstream claim per the
identity-claim guidance
— Entra oid, never an email. Then tell the server to match the claim against
the external_id column, and provision users with friendly ids:
# deploy/.env
PRECIS_IDENTITY_COLUMN=external_id
python -m precis_mcp.admin_cli create-user --id alice --no-keycloak \
--external-id <idp-stable-id>
--no-keycloak because the broker creates the Keycloak record at first
login — don't create a local password account beside it.
PRECIS_IDENTITY_COLUMN is deployment-wide: once it's external_id, give
every user an external id, including local-account users (theirs can simply
repeat the user id: --external-id alice).
B. Set the attribute by hand (small teams). Keep the default
PRECIS_IDENTITY_COLUMN=id. After each user's first brokered login, open
their record in the Keycloak console (Users) and set precis_user_id to
their platform user id. No IdP mapper, no env change — one manual step per
user, which stops scaling around a dozen users.
Step 4 — provision and verify¶
Creating the user (step 3) is only half of provisioning — being able to sign
in grants nothing until a profile is
assigned. Without one the user authenticates, but every scenario-scoped tool
(run_metric, run_statement, inspect_rows, …) is hidden from their
client's tool list. Create a profile and assign it:
python -m precis_mcp.admin_cli profile create --file analyst.yml
python -m precis_mcp.admin_cli assign --user alice --profile analyst
What a profile contains — scenario patterns, roles, domain and dimension scopes, with worked examples — is documented in User profiles & permissions; the wider provisioning flow is the same as in Remote access.
Verify end to end:
python -m precis_mcp.admin_cli check-authpasses.- Connecting an MCP client lands on your corporate login page, not a Keycloak form.
- The connected client's tool list includes
run_metricandrun_statement(a partial list with only master-data and ops tools means no profile is assigned), and a report query returns data. - A colleague who exists in your IdP but is not provisioned in
Précis-MCP signs in successfully and is still refused (
403, not provisioned) — that's the provisioning gate doing its job.
The DCR and admin surfaces¶
The bundled realm deliberately accepts anonymous client registration: the
per-deploy reconcile removes Keycloak's anonymous-DCR-blocking policies
(Trusted Hosts, Consent Required, Allowed Client Scopes) so that claude.ai and
ChatGPT can self-register. Registering a client grants no access to data:
a registered client still has to send a real user through your brokered
sign-in, and that user must exist in Précis-MCP with a profile. Keycloak's
remaining anonymous-registration limits (such as the max-clients cap) stay in
place. It is still an unauthenticated write surface. The reference nginx
config (deploy/nginx/) ships the edge mitigations; if you write your own
ingress, reproduce them:
- Rate-limit the registration path —
/auth/realms/precis/clients-registrations/. Both reference ingresses do this per IP at 5/min: the bundled Caddy proxy via arate_limitzone (the proxy image compiles inmholt/caddy-ratelimit— not in stock Caddy) and the nginx config vialimit_req(burst 5). Note neither prevents eventual exhaustion of Keycloak's max-clients cap by a patient attacker — rate limiting throttles churn; the cap bounds the total; if the surface worries you, close it (below). - Restrict the admin console. Both the bundled Caddy proxy and the
reference nginx config block
/auth/admin/at the edge; reach the console over an SSH tunnel to127.0.0.1:8080, or relax the block to an IP allowlist for a trusted range. Nothing in normal operation needs it publicly — MCP clients never touch it, and the realm reconcile runs container-to-container. - Not using the public connectors? If only pre-registered clients ever connect, close the surface: re-add the Trusted Hosts anonymous policy (realm → Client registration → Client registration policies) or block the registration path at the ingress outright.
- Watch the client list for registrations you don't recognise.
Related¶
- Remote access — sign-in & identity modes — mode B itself: variables, bring-up, provisioning.
- External IdP recipes — when to broker vs trust your IdP directly (mode C), and the per-IdP token mechanics.
- User profiles & permissions — what a provisioned user may read.