CREATE USER ... IDENTIFIED WITH jwt statement, and attempting it raises an exception. JWT users are fully managed by the token lifecycle.
Overview
The authentication flow works as follows:- A client presents a signed JWT via one of the supported transport mechanisms (HTTP
Authorization: Bearerheader, the TCP native protocol, or the gRPCjwtfield). - ClickHouse validates the token signature.
- Required claims (
exp,iat,iss,sub,aud) are verified. - An ephemeral user is created in memory with access rights derived from the
clickhouse:grantsandclickhouse:rolestoken claims, intersected with a permission limit. - When the token expires, a background garbage collection task removes the user.
Token claims
Required claims
Every JWT presented to ClickHouse must contain the following claims:
The
kid (key ID) header claim is also required when JWKS-based key resolution is used.
JWKS mode supports RSA keys onlyWhile static-key providers accept any of
HS256, RS256, or ES256, JWKS-based providers only accept JWKs whose kty is RSA (i.e., tokens signed with RS256). Tokens signed with HMAC (HS256) or EC (ES256) keys cannot be verified against a JWKS endpoint and will be rejected.Other recognized claims
Optional claims
Example token header and payload
Ephemeral user behavior
JWT users differ from regular ClickHouse users in several important ways.Identity and naming
Each JWT user receives a deterministic UUID computed from theiss, sub, and aud claims. This UUID is stable across logins. A user who logs in multiple times with different tokens (but the same issuer, subject, and audience) always gets the same UUID.
The username, however, is volatile. It is constructed as:
<claims_hash> portion changes whenever the clickhouse:roles or clickhouse:grants claims change. This means that tokens with different role or grant sets produce different usernames even for the same identity.
Access rights
Effective access rights are computed as:permission_limit is the set of access rights held by a reference role or user configured as the upper bound. Rights requested by the token that exceed the limit are silently dropped.
Token freshness
ClickHouse tracks theiat (issued-at) claim of the most recently authenticated token for each stable identity. If a token with an iat equal to or older than the stored value is presented, the server reuses the existing ephemeral user without re-evaluating claims. This prevents older tokens from downgrading a user’s permissions.
Lifetime and garbage collection
Ephemeral users are created when a token is first authenticated and removed by a background garbage collection task aftervalid_until (derived from exp) passes. The GC interval is controlled by the gc_interval parameter (default: 5 minutes).
Between GC runs, expired users may still be visible in system.users but can no longer authenticate.
Persistent access assignments
Because the UUID is stable, you can assign settings profiles, quotas, row policies, and column masking policies to a JWT user using SQL statements. These assignments persist in the access control storage (on disk or in ZooKeeper) and survive token expiry and re-authentication. Reference the user by their current username:The username and UUID for a given identity can be found in the
name and id columns of system.users while the user is active.ALTER USER does not work on JWT users directly, as they are read-only. To assign settings profiles, quotas, or policies, use the ALTER SETTINGS PROFILE, ALTER QUOTA, or ALTER ROW POLICY statements as shown above.
Differences from regular users
SQL SECURITY DEFINER views
When an ephemeral JWT user creates a view withSQL SECURITY DEFINER, the server automatically creates a persistent shadow copy of the user to serve as the view’s definer. This shadow user:
- Has the name
<original_jwt_username>:definer - Has
NO_AUTHENTICATION(cannot be used to log in) - Retains the same access rights as the original JWT user at the time the view was created
Client usage
Passing a token directly
Use the--jwt flag with clickhouse-client to authenticate with a pre-obtained token:
The
--jwt flag is mutually exclusive with --user. When --jwt is specified, the username is derived from the token.HTTP interface
Send the token as a Bearer token in theAuthorization header:
OAuth2 device code login
Theclickhouse-client supports an interactive OAuth2 device code flow via the --login flag. For ClickHouse Cloud endpoints, the client automatically performs token exchange to obtain a ClickHouse-specific JWT. Tokens are refreshed transparently during the session. When a new token is obtained, the client reconnects automatically.
ClickHouse Cloud built-in JWT authenticator
Every ClickHouse Cloud service comes with a predefined JWT authenticator that is used by SQL Console and theclickhouse-client --login flow. This authenticator is configured with:
The built-in authenticator has a permission limit set to the
default_role role and the default user. This means the effective rights of any JWT user are intersected with the grants held by those two entities, so a token can never escalate privileges beyond what default_role and default are allowed to do.
You do not need to configure anything to use this authenticator. It is provisioned automatically when the service is created.
Interserver communication
When a query is forwarded to another shard or replica, the JWT token is included in the interserver protocol. The remote node re-authenticates the token independently, creating its own ephemeral user.Troubleshooting
- No access rights granted: The referenced role or user may lack the required grants. Ensure the roles referenced in the
clickhouse:rolesexist and include the appropriate grants. - Token rejected: Verify that
iss,aud, and the signing algorithm in your token match what the JWT provider expects. If JWKS is used, ensure the token’skidmatches a key in the provider’s key set. - User disappears between queries: Ephemeral users are removed after token expiry. Use a client that supports token refresh (e.g.,
--loginmode) for long-running sessions. CREATE USER ... IDENTIFIED WITH jwtfails: This is expected. JWT users cannot be created via DDL. They are managed entirely by the token lifecycle.