Direct Cloud database connections with JWT auth (no password, no Query API key)

Open
#1,154 1 comment 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
25/100
Issue type
Feature
Clarity
Needs clarification
Activity status
Active
Tech stack
rust
Domain
cli, cloud

Research direction

Start by reading crates/clickhousectl/src/cloud/auth.rs and tracing how the existing cloud service client and cloud service query commands obtain credentials. The issue leaves key dependencies unresolved, including whether token exchange is supported and how direct connections handle access controls. Done means those questions have answers and the implementation scope for the proposed phases is clear.

Written by the indexing model from the issue text.

Description

cloud enhancement

End result

A user who has run clickhousectl cloud auth login can work with a Cloud ClickHouse service directly, with no password and no Query API key:

clickhousectl cloud service client --name prod        # interactive clickhouse-client session
clickhousectl cloud service query --name prod -q '…'  # SQL over direct HTTPS instead of the Query API
clickhousectl cloud service token --name prod         # short-lived token for a driver or script

Each connection runs as the user's own Cloud identity, with rights capped at the service's default user, and the token expires on its own.

What it improves

  • Connecting without a password. Today the default user's password is only shown by service create and reset-password. That is why we removed cloud service client: it needed both a 200 MB local binary and that password. With JWT auth the password problem goes away, and the binary becomes optional rather than required.
  • No minted or bound Query API keys for OAuth users. cloud service query currently provisions or binds a Query API key (#1043). A direct connection would just use the user's token.
  • The full ClickHouse interface. Every output format, streaming, session settings and the native protocol, instead of the Query API's single statement per request.
  • Audit. Queries show up as the person who ran them (JWT::<email>::…), not as default.

How it works today (research, 2026-10-30)

  • Cloud services accept a short-lived JWT over HTTPS (Authorization: Bearer) and native TCP. The built-in Cloud authenticator is listed for all plans. Its tokens carry iss=ClickHouse, aud=<service UUID> and sub=<account email>. A session runs as an in-memory user JWT::<sub>::<hash>, limited to default + default_role and further narrowed by the token's grant and role claims. The user expires at exp. Sources: https://clickhouse.com/docs/concepts/features/security/external-authenticators/jwt, https://clickhouse.com/blog/introducing-jwt-authentication-in-clickhouse-cloud
  • clickhouse-client --jwt <token> was added in PR ClickHouse/ClickHouse#62829 (24.7, inferred). clickhouse-client --login (ClickHouse/ClickHouse#89261, 25.12, inferred) runs the whole flow itself and refreshes the token during a session. Its flow, from src/Client/CloudJWTProvider.cpp:
    1. An Auth0 device flow at auth.clickhouse.cloud with audience token-exchange.
    2. POST https://console-api-internal.clickhouse.cloud/.api/auth/tokenExchange with the IdP token as Bearer and body {"hostname": "<service host>"}.
    3. The response is {"token": "<ClickHouse JWT>"}.
  • The public OpenAPI (/v1) has no endpoint that issues database tokens.
  • clickhousectl's own OAuth token uses audience clickhousectl (crates/clickhousectl/src/cloud/auth.rs), not token-exchange.
  • Drivers already accept a bearer token: clickhouse-js and clickhouse-connect (access_token), Go (GetJWT), Java (useBearerTokenAuth), and Rust (clickhouse crate, Client::with_access_token).
  • Cloud Postgres services: we found no JWT support; credentials there are still a password.

Proposed phases

  1. cloud service client, delegating to clickhouse-client --login. If a local clickhouse-client ≥ 25.12 is installed (or one that local install manages), exec clickhouse-client --host <service host> --secure --login. The client owns the token, so this needs nothing new from Cloud. It still needs a human to complete the device flow in a browser.
  2. Direct cloud service query for OAuth sessions. Exchange the CLI's token for a database JWT and send SQL over HTTPS from Rust. Keep the Query API path for API-key auth, CI and agents. Needs a supported exchange (see below).
  3. cloud service token / a JWT in cloud service dotenv. Hand a short-lived token to drivers and scripts. Same dependency as phase 2.

What we need to resolve (Cloud team)

  1. Will /.api/auth/tokenExchange become a supported public contract, or get a /v1 equivalent? Can third-party clients such as clickhousectl rely on it?
  2. Can the exchange accept clickhousectl's Auth0 audience or client, or should the CLI also request token-exchange?
  3. Can an organization API key be exchanged for a database JWT? This would serve CI and agents, which can't do a device flow.
  4. What is a token's lifetime, and is there refresh or revocation?
  5. Can a token carry rights narrower than default, for example a read-only mode?
  6. Does the built-in authenticator need enabling per service? The activity log has a service_update_sql_console_jwt_auth type.
  7. How do direct connections behave with IP access lists and private-endpoint-only services, which the Query API handles today? How does an idle service wake on a direct connection?
  8. Is JWT auth planned for Cloud Postgres?

Not in scope

  • Bring-your-own-identity-provider JWT (Enterprise, configured per service in the console).
  • Postgres, until question 8 is answered.

🤖 Generated with Claude Code

Dominant language
Rust
Stars
80
Forks
9
Avg merge
2d 18h
Merged PRs (30d)
51

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from ClickHouse/clickhousectl

All issues in ClickHouse/clickhousectl

Similar issues

More Rust issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.