Identity providers
ZeroClaw signs people in through OpenID Connect, and it is strict about the access token a provider issues. Most providers need settings changed, and some don’t work yet. This page lists what a provider needs, the providers tested with v0.9.0 pre-release builds, the ones known not to work yet, and the current limitations. Only the providers under Tested providers are known to work. To configure a provider, see OIDC and Dashboard sign-in.
The daemon verifies every access token with the same rules, whether it arrives through dashboard sign-in or from a native client (zerocode, or a token from zeroclaw oidc login), so a provider whose access token is refused is refused everywhere. zeroclaw oidc login and zeroclaw oidc token only fetch a token and print it. A sign-in that succeeds there doesn’t show that the daemon accepts the token.
What a provider needs
- Discovery.
<issuer>/.well-known/openid-configurationmust name exactly the configuredissuer, trailing slash included. - PKCE with S256, for browser sign-in. Dashboard sign-in,
zeroclaw oidc login --browserand the gateway’s browser enrollment need the discovery document to listS256incode_challenge_methods_supported. They refuse an issuer that leaves the field out, because a missing field means no PKCE, andplainis never accepted. The device grant andclient_credentialsdon’t read this field. - The device grant, for
zerocodeandzeroclaw oidc login.zerocode, andzeroclaw oidc loginwithout--browser, sign in with the Device Authorization Grant (RFC 8628), so the provider must offer it and listdevice_authorization_endpointin discovery. Dashboard sign-in doesn’t use it. - An access token ZeroClaw can verify, through one of the two
validationmodes:jwks: an RFC 9068 JWT access token, with the headertypat+jwt(orapplication/at+jwt), signed with RS256 or ES256. It must carryiss,aud,exp,iatandjti, and name its client inclient_id(for a person’s token,azpis accepted instead). Every key in the issuer’s key set needs its ownkid. A JWT typedJWTor with notyp, which is what many providers issue by default, is refused, because it can’t be told apart from an ID token.introspection: RFC 7662 token introspection whose answer carriesactive: true,token_type: Bearer, the configuredaudienceand aclient_id. The discovery document must listintrospection_endpoint. This mode needs the entry’sclient_secret.
- Nothing that marks it as another kind of token. In either mode, the token (or the introspection answer) must not carry a
nonceclaim. Atyportoken_useclaim, if present, must name an access token:typBearerorat+jwt, andtoken_useexactlyaccess. - The audience. The access token’s
audmust contain the configuredaudience. - Roles or groups without an extra scope. ZeroClaw requests only the
openidscope, so the values atclaim_pathmust be in the access token (or the introspection answer) by default. Otherwise, map people one by one, for example withclaim_path = "sub". - Client authentication by request. The authorization-code exchange (dashboard sign-in,
zeroclaw oidc login --browserand the gateway’s browser enrollment) sends theclient_secretin the form body (client_secret_post). Introspection, the device grant andclient_credentialssend it with HTTP Basic (client_secret_basic). A provider that accepts only the method registered for a client may need a separate[oidc.<alias>]entry and client for the device grant orclient_credentials. Dashboard sign-in withintrospectioncan’t be split that way: one client makes both the exchange and the introspection call, so it has to accept both methods. - A working-session token lifetime, such as one to eight hours. The dashboard doesn’t use refresh tokens, so a session ends when its access token expires.
Tested providers
Each provider below signed in an administrator and a member account through dashboard sign-in, with the profiles their claims map to. On the bearer path, the same provider’s ID token, refresh token, and an access token issued to another of its clients were each refused. The tests ran against v0.9.0 pre-release builds in October and November 2026. Keycloak was tested with the gateway on plain HTTP and on its own TLS listener, and with zerocode and zeroclaw oidc login. Zitadel and Authelia were tested with dashboard sign-in only.
| Provider | Version tested | validation |
|---|---|---|
| Keycloak | 26.8.0 | jwks or introspection |
| Zitadel, self-hosted | v4.20.1 | introspection |
| Authelia | 4.39.28 | jwks |
Keycloak
- Turn on the client’s RFC 9068 access-token header (
access.token.header.type.rfc9068 = true), require PKCES256, and set an access-token lifespan of one to eight hours. Keycloak’s default is five minutes. - Add an audience mapper that puts the configured
audiencein the access token. - Add a group membership mapper with the token claim name
groups, without full paths, forclaim_path = "groups". - The tested client also had a hard-coded
client_idclaim mapper. Without one, see Keycloak access-token client attribution. - For
introspection, also add an audience mapper with the client’s own client ID. Keycloak 26.6.2 and later answer introspection as inactive for a token that doesn’t name the asking client.
Zitadel
- Create a Web application whose authentication method is Code (HTTP Basic) or Post. Both were tested. Don’t pick the PKCE method: it creates a client without a secret, and
introspectionneeds one. ZeroClaw sends a PKCE challenge with either. - Give each person a role in the project. The tested project also had role assertion turned on.
- Set
audienceto the project ID andclaim_path = "urn:zitadel:iam:org:project:roles". jwksdoesn’t work: Zitadel’s access tokens are opaque, or JWTs typedJWT.
Authelia
- Register the client with
token_endpoint_auth_method: client_secret_post,access_token_signed_response_alg: RS256and PKCES256. The defaultclient_secret_basicfails the code exchange. - Set the client’s
audienceto the configuredaudience, withrequested_audience_mode: implicit. Authelia’s default,explicit, adds an audience only when the client asks for one, and ZeroClaw doesn’t. - Map people one by one (
claim_path = "sub"). Authelia’s group claim needs agroupsscope, which ZeroClaw doesn’t request. introspectiondoesn’t work: Authelia’s introspection answer has notoken_type.- Authelia serves its issuer over HTTPS only, so its certificate must chain to a certificate authority the daemon trusts (see Limitations).
Known not to work yet
These were tested and have no configuration that works in v0.9.0:
- Dex (v2.46.1). Its JWT access tokens have no
typin their header and carry the sign-in nonce, and its introspection marks tokenstoken_use: access_tokenwhile answering for its ID tokens the same way. Accepting that would let an ID token be used as an access token, so it stays refused. - Authentik (2026.8.5). Its access token is typed
JWTand carries the sign-in nonce, and its introspection answer has notoken_type. - Logto (1.45.0, tested with
zeroclaw oidc loginand not with the dashboard). Its access tokens for people are opaque unless the token request names an RFC 8707resource, which ZeroClaw doesn’t send yet. So people can’t sign in. A Logto service client usingclient_credentialsworks only with a default API resource set and Logto’s signing key rotated to RSA: its default key signs with ES384, which ZeroClaw doesn’t verify.
Not tested. Going by their documentation, published discovery documents and source, these aren’t expected to work yet:
- Amazon Cognito. Its discovery document doesn’t list
S256, its access tokens have notypin their header, and it has no introspection endpoint. - Ory Hydra (v26.2.0). Its JWT access tokens are typed
JWT, and its introspection is served only on its admin port and isn’t in discovery.
Any other provider, hosted or self-hosted, hasn’t been tested. Check it against What a provider needs. The usual blockers are access tokens that aren’t typed at+jwt, opaque tokens without introspection, and discovery that doesn’t advertise S256.
Limitations in v0.9.0
- No RFC 8707
resourceparameter. Providers that issue a verifiable access token only for a named resource, such as Logto, can’t sign people in yet. - No configurable scopes. Every request asks for
openidonly, so claims that a provider releases only for another scope (oftengroups) never arrive. - No private certificate authority per provider. The issuer’s TLS certificate must chain to a certificate authority the daemon already trusts. There’s no setting to add one for a single provider.
- The CLI’s gateway admin commands don’t work when the gateway serves TLS itself (#12091).
- The affected commands are
zeroclaw gateway get-paircodein every form,zeroclaw sop pending,logs,approveanddeny, andzeroclaw gateway restart. - They always connect over plain
http://, so with[gateway.tls]enabled they fail with “Failed to connect to gateway”. zeroclaw gateway restartreads that failure as “no gateway running” and tries to start a second one on the same address.
- The affected commands are
- A provider outage when a session is verified again signs dashboard users out (#12096).
- The gateway verifies a signed-in session’s token again:
- at each introspection revalidation deadline (
revalidation_secs); - after a configuration reload, in either
validationmode; - when its grants check fails because the policy changed (a change to
[oidc],[users],[permission_profiles]orsecurity.trust_daemon_uid).
- at each introspection revalidation deadline (
- If the provider can’t be reached then, or answers with an error, the session ends. It fails closed: nothing is admitted that shouldn’t be.
- The dashboard reports the session as expired. The gateway logs the real cause as
dashboard session ended: verifying its token again failed. - Users sign in again once the provider is back.
- Without a reload or a policy change, a
jwkssession isn’t verified again. It keeps its verified identity until its token or the session expires, however long the provider is down. - The five-minute key cache matters only for a token that is presented fresh, such as a new
zerocodeconnection. That token is verified from cached keys for up to five minutes after the last key fetch, and refused after that until the provider answers. A reload or a policy change starts with no cached keys.
- The gateway verifies a signed-in session’s token again:
- A scoped account’s dashboard chat lasts only as long as its connection. Reloading the page, leaving the chat, or a dropped connection ends the conversation, and a new chat starts a new one. The transcript is kept, but the dashboard can’t reopen it. See Dashboard sign-in.