CL
Clausgap
/Docs

Connecting your identity provider

Clausgap needs to know two kinds of identity:

  • People — admins, policy authors, reviewers and approvers. They sign in to the dashboard through your organisation's identity provider (IdP) with single sign-on.
  • Agents — every request an agent sends through the proxy must say which agent it is, in a way the proxy can verify. The same IdP can issue agents signed tokens; API keys and signed SDK requests work too.

You can try every step below — with a test identity provider standing in for yours — in the evaluation kit, which also checks each step end to end.

People: single sign-on

1. Register Clausgap with your IdP

In Okta, Entra ID, Google Workspace, Auth0, Keycloak or any OIDC provider, create a web application (OIDC, authorization code flow):

SettingValue
Redirect / callback URLhttps://<your dashboard>/api/auth/sso/callback
Scopesopenid email profile
Assigned usersEveryone who should use Clausgap

Note the issuer URL, the client ID and the client secret.

2. Connect it and verify your domain

Sign in as an admin, go to Settings → SSO and enter the issuer, client ID and secret. Clausgap checks the issuer straight away by fetching its discovery document, so a wrong issuer fails here, not at someone's first sign-in.

Then add your email domain — for example example.com — and prove you own it. Clausgap shows a DNS TXT record to publish:

NameValue
_clausgap-verification.example.comclausgap-domain-verification=<token>

Publish it with your DNS provider, then select Verify. Until a domain is verified, no sign-in is routed through it. Only one organisation can verify a given domain, so nobody can claim your domain and send your people to their identity provider. You can remove the record after verification.

The API equivalent, with an admin session:

text
PUT  /v1/settings/sso                             {"issuer_url": "...", "client_id": "...", "client_secret": "..."}
POST /v1/settings/sso/domains                     {"domain": "example.com"}   → domain_records[].txt_name / txt_value
POST /v1/settings/sso/domains/example.com/verify

From then on, anyone who enters an address in that domain on the sign-in page is sent to your IdP.

3. Give people roles

Roles live in Clausgap:

RoleCan
viewerSee everything; change nothing
authorCreate and edit policies, and submit them for review
approverApprove or reject policy changes and held agent actions
adminEverything, including SSO, team, settings and break-glass

Invite people from Team, with their role. When they first sign in through the IdP, they have the invited role — the invite and the SSO sign-in are the same account, matched by email. Someone who signs in through SSO without an invite gets an account with no roles, and can't change anything until an admin grants one.

Clausgap only accepts an SSO sign-in when both of these hold:

  • the email is in one of your verified domains;
  • your IdP hasn't marked the email as unverified (email_verified: false).

4. People leaving

Removing someone in Team ends their sessions at once and takes away their roles. They then can't sign in again by any route — SSO or emailed link — until an admin invites them again, which restores the same account. Disable them in your IdP as well, as usual.

Requiring a second person for policy changes

Turn on Settings → Require approval. From then on, a policy change only takes effect once someone other than its author approves that exact version — whether it came from the dashboard, the API or a CI pipeline. Until then, proxies keep enforcing the last approved version. Break-glass (admins only, with a reason) deploys a change immediately and is recorded at critical severity; turning approval off is recorded too.

Agents: identity the proxy can verify

An agent's identity decides which policy applies to it, so it must come from something the agent can't forge. Clausgap never takes it from plain request headers — X-Agent-Role: admin from a caller changes nothing. Choose one of these per agent.

Tokens from your IdP (JWT)

Use this when your agents already get tokens from your IdP — client credentials, workload identity, or a service account. Register the IdP as a token issuer, with the tenant's API key or an admin session:

json
// POST /v1/keyless/jwt-providers
{
  "name": "Corporate IdP",
  "issuer": "https://login.example.com/",
  "jwks_uri": "https://login.example.com/.well-known/jwks.json",
  "audience": "clausgap",
  "allowed_algorithms": ["RS256"],
  "claims_mapping": { "agent_role": "clausgap_role", "agent_id": "sub" }
}

The agent sends Authorization: Bearer <token>. The proxy checks the signature against the IdP's published keys (JWKS), the issuer, the audience and the expiry; claims_mapping names the claim that carries the agent's role. The proxy rejects a token with an edited claim, an unsigned token (alg: none), a token issued to a different application (wrong audience), and any algorithm you didn't allow.

API keys

Issue an agent a key with a role and, optionally, the networks it may be used from:

json
// POST /v1/keyless/api-keys
{
  "name": "reporting agent",
  "key_value": "<a long random secret you give the agent>",
  "agent_role": "reporting_agent",
  "agent_id": "reporting-1",
  "allowed_cidrs": ["10.20.0.0/16"]
}

The agent sends the key in the header you configure, for example X-Agent-Key. Revoking it (DELETE /v1/keyless/api-keys/{id}) takes effect when the proxy next refreshes its credentials — every keyless.poll_interval, 30 seconds by default.

The same key in direct mode. An agent using a framework integration can use its agent key instead of the tenant API key: give the SDK the key and set CLAUSGAP_TENANT_ID (sent as X-Clausgap-Tenant). The key decides who the agent is — a request naming another role or agent is refused (403 IDENTITY_MISMATCH) — and it can only evaluate tool calls and read its own holds, never create policies or issue keys. Its allowed_cidrs, expiry and revocation apply, and Discovery Mode lets a direct-mode call through only with an agent key. A tenant API key still works in direct mode, but lets the agent name any role and can do everything the tenant can: keep those for pipelines and the proxy.

Signed SDK requests

The Python and TypeScript SDKs sign each request's identity with a secret shared with the proxy (hmac_secret on the HTTP listener). The signature covers the method, the path, the body and a timestamp, so a captured request can't be replayed or altered. Give each agent its own secret bound to its role under signing_keys on the HTTP or MCP listener: a header signed with it must claim that role. The single shared hmac_secret still works, but anyone holding it can sign as any role, and Discovery Mode never lets its callers through. See Direct HTTP & SDK.

Behind a load balancer

If the proxy or control plane sits behind a load balancer, list it in trusted_proxies so client addresses come from the forwarded header it adds. Without this, per-IP rate limits and allowed_cidrs see the load balancer's address; with it, a client can't set its own address, because only hops you trust are believed.

yaml
trusted_proxies: ["10.0.0.0/8"]
client_ip_header: "X-Forwarded-For"
ℹ

Known limit: IdP groups don't map to Clausgap roles yet — roles are given by invite or by an admin in Clausgap.