Skip to main content
CockroachDB supports SASL OAUTHBEARER (RFC 7628) authentication for SQL client connections. With OAUTHBEARER, a SQL client presents an OAuth 2.0 bearer token issued by your identity provider (IdP), such as Okta, Keycloak, Microsoft Entra ID, or Google, and CockroachDB validates the token and maps it to a SQL user. The token must be a JWT. CockroachDB cannot validate opaque access tokens. For example, Google issues opaque access tokens, so the device flow does not work with Google. Only a Google ID token presented by a driver can be validated. The protocol matches the OAuth support in PostgreSQL 18, so psql 18, libpq 18, and PostgreSQL-compatible drivers that implement OAUTHBEARER can authenticate to CockroachDB without any CockroachDB-specific client logic. This page describes how to configure a cluster for OAUTHBEARER authentication, how to connect with cockroach sql, psql, and other clients, and how to manage users that the cluster provisions automatically.

Overview

CockroachDB offers two ways to authenticate SQL clients with tokens from an external IdP:
  • SASL OAUTHBEARER (this page): the client sends a bearer token in a standard SASL exchange. The client can obtain the token itself, or cockroach sql and psql 18 can run an interactive OAuth 2.0 device authorization flow in a browser and connect with the resulting token. Use this method when your clients support OAUTHBEARER natively.
  • : the client sends a JSON Web Token (JWT) in place of a password. Use this method with clients that do not implement OAUTHBEARER but accept a long password.
Both methods validate the same token properties (issuer, signing key, expiry, and audience), and both support automatic user provisioning and group-based role synchronization. The two methods are configured with separate cluster settings and separate methods, so you can enable either or both. The methods differ in two ways: OAUTHBEARER requires the identity claim to hold exactly one value (refer to Step 1), and OAUTHBEARER does not cache JWKS keys between logins. When OAUTHBEARER authentication is enabled, a node handles each login as follows:
  1. The client connects over TLS and requests a SQL user. The server advertises the OAUTHBEARER SASL mechanism.
  2. The client sends a bearer token. If the client has no token yet, it sends an empty token, and the server responds with the information the client needs to obtain one (refer to Error response).
  3. The server reads the token principal from the configured claim, before the token is verified, and, if an identity map is configured, maps it to a SQL username. The result must match the SQL user that the client requested.
  4. If the user does not exist and automatic user provisioning is enabled, the server verifies the token’s signature against the issuer’s JSON Web Key Set (JWKS) and checks its issuer, then creates the user.
  5. The server fully validates the token: signature, issuer, expiry, and audience.
  6. If group-based authorization is enabled, the server synchronizes the user’s role memberships from the token’s group claim.
Authentication events are recorded in the logging channel.
OAUTHBEARER authentication cannot be used for the root user or other . Credentials for root must be managed separately using password or certificate authentication to ensure continuous administrative access regardless of IdP availability.

Prerequisites

  • An identity provider that issues JWT-format OAuth 2.0 access tokens and publishes its signing keys as a JWKS, typically through an OpenID Connect discovery document at https://{issuer URL}/.well-known/openid-configuration.
  • A cluster that is fully upgraded to v26.4. The oauth HBA method is gated on the v26.4 cluster version. If you configure it before the upgrade is finalized, the SET CLUSTER SETTING statement fails with an ObjectNotInPrerequisiteState error.
  • A secure cluster. The oauth HBA method is accepted only on TLS connections.
  • The ability to update cluster settings. Refer to .
  • SQL users that correspond to your external identities, unless you enable automatic user provisioning. To create users, you must have access to the .
  • For the interactive device flow with cockroach sql or psql, an OAuth client registered with your IdP as a public client (no client secret) with the device authorization grant enabled, and an issuer that is reachable over HTTPS.
Before you begin, enable authentication logging to help confirm your configuration or troubleshoot issues. Refer to Troubleshooting.

Configuration

Step 1: Configure cluster settings

OAUTHBEARER authentication is controlled by the in the following table. Each setting applies only to OAUTHBEARER logins; the for cluster SSO using JWTs are separate. A minimal configuration enables the method, trusts one issuer, fetches that issuer’s signing keys automatically, restricts the audience, and names the claim that holds the username:
To accept more than one issuer, set server.oauthbearer_authentication.issuers to a JSON array, or to a JSON object when an issuer’s JWKS is not discoverable from its .well-known/openid-configuration endpoint:
Discovery-driven clients such as psql 18 rely on the server to advertise the issuer’s OpenID configuration endpoint, and the server does so only when exactly one issuer is configured. If you configure several issuers, clients must be told the issuer explicitly (for example, with --oauth-issuer in cockroach sql), or must obtain a token on their own.
If you prefer static signing keys, leave server.oauthbearer_authentication.jwks_auto_fetch.enabled at false and set server.oauthbearer_authentication.jwks to the JWKS published by your issuer. IdPs rotate their signing keys periodically, so you must update the static key set before the previous keys expire, or OAUTHBEARER logins will fail. Automatic fetching avoids this maintenance. Because the identity map and the HBA configuration can contain information you may not want all users to see, consider enabling redaction of those settings. Refer to .

Step 2: Configure host-based authentication (HBA)

To enable OAUTHBEARER for a set of users, add a rule with the oauth method to the configuration in the cluster setting server.host_based_authentication.configuration. The simplest rule allows every user from every address to authenticate with a bearer token:
The oauth method accepts two options, each of which may appear at most once on a rule:
  • map=<map name>: apply the named identity map from server.identity_map.configuration to translate the token principal into a SQL username. Without map=, the value of the configured claim is used directly as the SQL username, so it must equal the username the client requests.
  • issuer=<issuer URL>: accept only tokens issued by this issuer on this rule. The URL must be one of the issuers configured in server.oauthbearer_authentication.issuers. Without issuer=, a token from any configured issuer is accepted. Use this option to pair different issuers with different identity maps or user sets.
For example, the following configuration maps principals from https://auth.example.com through the crdb identity map, and falls back to certificate or password authentication for anyone else:
Keep the following in mind:
  • The oauth method is accepted only on TLS connections. A client that matches an oauth rule over a non-TLS connection is rejected with method "oauth" required for this user, but unusable over this connection type.
  • Any option other than map and issuer is a configuration error, and the SET CLUSTER SETTING statement fails.
  • Setting an oauth rule before every node is running v26.4 and the upgrade is finalized fails with an ObjectNotInPrerequisiteState error.
  • root and other cannot log in with OAUTHBEARER, whether or not an identity map is used. The mandatory root rule continues to allow root to authenticate with a certificate or password.

Step 3: Map identities (optional)

If the usernames in your tokens do not match your SQL usernames exactly, configure an identity map in the cluster setting server.identity_map.configuration and reference it from the HBA rule with map=<map name>. The format follows PostgreSQL’s pg_ident.conf: each line is a space-separated triple: <map name> <token principal or regular expression> <SQL username>
  • <map name> is the name you pass to map= in the HBA rule. One configuration can hold several maps.
  • <token principal or regular expression> is matched against the value of the claim named by server.oauthbearer_authentication.claim. A value that starts with / is interpreted as a case-insensitive regular expression; anchor it with ^ and $ to avoid partial matches. The expression may contain one capturing group.
  • <SQL username> is the SQL user the principal may log in as. It can include \1 to substitute the capturing group.
This differs from the identity map used by , where the first field is the issuer URL rather than a map name. For OAUTHBEARER, pin a rule to an issuer with the issuer= HBA option instead.
For example, the following map lets any @example.com email address log in as the SQL user named by the part before the @, and lets the fixed subject 1232316645658094244789 log in as roach:
With this map and the rule host all all all oauth map=crdb, a token whose email claim is alice@example.com can log in as alice. The client still requests the SQL user to connect as (for example, --user=alice); the login fails if the mapped principal does not resolve to that user.

Step 4: Configure user creation

CockroachDB supports two approaches for the creation of users who authenticate with OAUTHBEARER: With automatic user provisioning, CockroachDB creates a SQL user during the user’s first successful OAUTHBEARER authentication. This eliminates the need to pre-create accounts for every identity in your IdP. When enabled:
  • Before the user is created, the token’s signature is verified and its issuer is checked, so only identities from your configured issuers can be provisioned. Expiry and audience are checked after provisioning, as part of full token validation.
  • The new user receives a PROVISIONSRC role option set to oauth:<issuer URL>, for example oauth:https://auth.example.com.
  • The estimated_last_login_time column of is tracked for auditing.
  • Auto-provisioned users cannot change their own passwords; their credentials are managed by the IdP.
The username is the mapped token principal and must meet the CockroachDB .
Before you enable automatic user provisioning, Cockroach Labs recommends that you enable group-based authorization and create the matching roles. This ensures that new users are members of the intended roles, with the privileges they confer, on their first login. Auto-provisioned users receive roles only for groups that already exist as CockroachDB roles.
To enable automatic user provisioning:
To view and manage auto-provisioned users, refer to Manage auto-provisioned users.

Option 2: Manual or scripted user creation

Alternatively, create users before they authenticate. The username must match the token principal after the identity map is applied.
To create users in bulk, produce a .sql file with one statement per user and run it with .

Step 5: Enable group-based authorization (optional)

CockroachDB can synchronize a user’s role memberships from the groups in their token on every OAUTHBEARER login, in the same way that does for cluster SSO using JWTs.
  1. Create CockroachDB roles whose names match your IdP group names, and grant privileges to those roles. Group names are normalized with case folding and Unicode normalization (NFC) before matching, so they typically match lowercase role names.
  2. Enable authorization and, if your IdP uses a claim other than groups, name the claim:
On each login:
  • The groups are read from the group_claim claim. If that claim is absent or malformed, the node queries the issuer’s userinfo endpoint with the access token and reads the userinfo_group_key key from the response. If the issuer’s discovery document has no userinfo_endpoint, the login fails with No userinfo endpoint. If the userinfo lookup fails, the login is rejected. If the userinfo response does not contain the userinfo_group_key key, all of the user’s direct role memberships are revoked and the login is rejected.
  • The claim is expected to be a JSON array of strings, for example ["developers", "analysts"]. If it is a single string, it is split on commas only, so "developers,analysts" yields two groups, while a name containing spaces, such as "data platform", is one group. Identity providers that convey multiple groups should return a JSON array.
  • Each group that matches an existing role is granted to the user. Groups that do not match a role are silently skipped.
  • Roles that the user holds but that no longer match a group are revoked. Roles held only through another role are not revoked individually.
  • If the group list exists but is empty, all of the user’s direct role memberships are revoked and the login is rejected with OAUTHBEARER authorization: empty group list.
  • Any role can be synchronized, including privileged roles such as admin. An IdP group named admin grants the admin role on login, and removing the user from that group revokes it. Control membership in such groups carefully in your IdP.
For IdP-specific guidance on exposing groups in tokens for Okta, Keycloak, and Microsoft Entra ID, refer to ; the same claim configuration applies to OAUTHBEARER tokens.

Connect to the cluster

Clients can authenticate with OAUTHBEARER in three ways.

Connect with cockroach sql using the device flow

can obtain a token for you by running the OAuth 2.0 device authorization grant against your IdP. Pass the issuer URL and the public OAuth client ID, and optionally the scopes to request:
The shell fetches the issuer’s discovery document, requests a device code, and prints a verification URL and a one-time code (opening a browser where one is available). After you sign in with your IdP, the shell receives the token and completes the SASL OAUTHBEARER exchange. No token is written to disk. Keep the following in mind:
  • --oauth-issuer and --oauth-client-id must be specified together.
  • The connection must use sslmode=verify-full. The shell refuses to send a bearer token over a plaintext connection, or over a TLS connection that does not verify the server’s identity, with an error such as refusing to send an OAuth token over a plaintext connection and the hint use sslmode=verify-full.
  • The issuer and the endpoints in its discovery document must use https. For local development against an IdP without TLS, set the environment variable COCKROACH_OAUTH_ALLOW_INSECURE_ISSUER=true. This relaxes only the check on the issuer’s endpoints, with a warning; the sslmode=verify-full requirement for the connection to CockroachDB still applies. Do not use this setting in production.
  • The SQL user in the connection URL must be the user that the token principal maps to.

Connect with psql 18 or libpq

PostgreSQL 18 libpq, and therefore psql 18 and clients built on libpq, implement OAUTHBEARER with a built-in device flow. Supply the issuer and client ID as connection parameters:
libpq verifies that oauth_issuer matches the OpenID configuration endpoint that the server advertises in its error response. CockroachDB advertises that endpoint only when exactly one issuer is configured in server.oauthbearer_authentication.issuers, so the libpq device flow requires a single-issuer configuration. If server.oauthbearer_authentication.scope is set, libpq requests that scope; otherwise, set oauth_scope in the connection string. For the full list of OAuth connection parameters, including oauth_client_secret and oauth_scope, refer to the PostgreSQL libpq documentation.

Connect with a driver and a pre-obtained token

Drivers that implement SASL OAUTHBEARER, such as pgx for Go, let your application supply a bearer token through a token-provider callback in the connection configuration. Your application obtains the token from the IdP by whatever OAuth flow suits it (for example, the client credentials grant for a service account) and the driver presents it when the server advertises OAUTHBEARER. The SQL user in the connection configuration must be the user that the token principal maps to through server.oauthbearer_authentication.claim and the identity map. Clients that do not implement OAUTHBEARER can still authenticate with a token by presenting it as a password. Refer to .

Manage auto-provisioned users

When automatic user provisioning is enabled, you can identify and manage auto-provisioned users with the following methods. For additional patterns, such as finding dormant accounts and cleaning up users removed from your IdP, refer to on the LDAP authentication page; the same statements apply with an oauth:<issuer URL> source.

View provisioned users

Auto-provisioned users can be identified by their PROVISIONSRC role option using the syntax:
Replace https://auth.example.com with your issuer URL. The source must match the full PROVISIONSRC value exactly; pattern matching is not supported.

Bulk-drop dormant provisioned users

To de-provision auto-provisioned users at scale, use . For example, to drop up to 100 users that were provisioned by your issuer and have not logged in since a specific date:
Preview the matching users first by running with the same clauses.

Restrictions on auto-provisioned users

Users created through automatic provisioning have specific restrictions:
  • Password changes: Auto-provisioned users cannot change their own passwords using ALTER USER, even if the cluster setting sql.auth.change_own_password.enabled is true.
  • PROVISIONSRC modification: The PROVISIONSRC role option cannot be modified or removed once set.
  • Authentication method: These users must authenticate through their IdP; password-based authentication is not available.

How it works

Authentication sequence

  1. SASL exchange: The client connects over TLS. If an oauth HBA rule matches, the server advertises the OAUTHBEARER mechanism and the client sends an RFC 7628 initial response containing auth=Bearer <token>.
  2. Identity mapping: The node parses the token and, before verifying it, reads the claim named by server.oauthbearer_authentication.claim (or sub), applies the identity map named by the rule’s map= option if any, and confirms that the result includes the SQL user the client requested and is not a reserved identity.
  3. Provisioning: If the user does not exist and security.provisioning.oauth.enabled is true, the node verifies the token’s signature against the issuer’s JWKS (static or auto-fetched) and checks that its iss claim is one of the configured issuers, then creates the user with PROVISIONSRC = oauth:<issuer URL>.
  4. Token validation: The node confirms that the token’s iss claim is one of the configured issuers (and matches the rule’s issuer= option, if set), verifies the signature against the issuer’s JWKS, and checks the expiry and the aud claim against server.oauthbearer_authentication.audience. With automatic fetching enabled, the node fetches the issuer’s discovery document and JWKS on every login; keys are not cached.
  5. Role synchronization: If server.oauthbearer_authentication.authorization.enabled is true, the node reconciles the user’s direct role memberships with the groups in the token.

Error response

When a token is missing or rejected, the server replies with an AuthenticationSASLContinue message whose body is the JSON error response defined in RFC 7628 §3.2.2:
Discovery-driven clients such as libpq deliberately send an empty token first to receive this response, then use the openid-configuration and scope values to obtain a token and reconnect. After sending the response, the server waits briefly for the client’s acknowledgement and then closes the connection with a generic authentication error. The detailed reason for the rejection is written only to the log, so that unauthenticated clients cannot learn about your configuration or which users exist. Malformed SASL messages, such as a request for channel binding (OAUTHBEARER-PLUS) or a non-empty authorization identity, are framing errors: the connection fails without an error response.

Troubleshooting

Enable to preserve data that will help troubleshoot OAUTHBEARER issues:
Once all functionality is configured and tested successfully, Cockroach Labs recommends disabling session logging to conserve system resources.
To view the logs, open cockroach-sql-auth.log from your . Clients receive only a generic error; the specific cause is in the log. Potential issues to investigate may pertain to:
  • ObjectNotInPrerequisiteState when setting the HBA configuration: The cluster is not yet fully upgraded to v26.4. Finish the upgrade and finalize it, then set the oauth rule.
  • method "oauth" required for this user, but unusable over this connection type: The client connected without TLS. Connect with sslmode=verify-full.
  • Invalid issuer: The token’s iss claim is not in server.oauthbearer_authentication.issuers, or does not match the issuer= option on the matching HBA rule.
  • Invalid audience: The token’s aud claim does not contain a value in server.oauthbearer_authentication.audience, or that setting is empty. Configure the IdP to issue tokens with an audience for CockroachDB and set the setting to match.
  • Signing key not found: With static keys, server.oauthbearer_authentication.jwks does not contain the key that signed the token. With automatic fetching, the node could not reach the issuer’s JWKS endpoint, possibly because of a private CA (set server.oauthbearer_authentication.issuers.custom_ca) or a timeout (server.oauthbearer_authentication.client.timeout).
  • Token principal does not map to the requested user: The claim named by server.oauthbearer_authentication.claim is missing from the token (the login fails with a missing-claim error; sub is used only when that setting is empty), or the identity map does not translate it to the SQL user the client requested. Check the map= option on the HBA rule and the lines in server.identity_map.configuration.
  • User does not exist: The mapped user has not been created and security.provisioning.oauth.enabled is false.
  • refusing to send an OAuth token over a plaintext connection: cockroach sql was run with the device flow but without sslmode=verify-full.
  • Issuer must use https: The device flow in cockroach sql rejected a plaintext issuer or endpoint. Use an HTTPS issuer, or for local development only, set COCKROACH_OAUTH_ALLOW_INSECURE_ISSUER=true.
  • psql cannot discover the issuer: More than one issuer is configured, so the server does not advertise an openid-configuration endpoint. Use a single issuer, or use a client that is told the issuer explicitly.
  • Empty group list or userinfo lookup failed: Group-based authorization is enabled and the user has no groups in the token, or the userinfo endpoint could not be queried. Refer to Step 5.

Security considerations

  1. Trust only known issuers: Any valid token from an issuer in server.oauthbearer_authentication.issuers can log in as, and with provisioning enabled create, a SQL user. Keep the list minimal, and use the issuer= HBA option to restrict which issuer applies to which users.
  2. Restrict the audience: Set server.oauthbearer_authentication.audience to a value that your IdP issues only for CockroachDB, so that tokens minted for other services cannot be replayed against the cluster.
  3. Prefer automatic key fetching: Enable server.oauthbearer_authentication.jwks_auto_fetch.enabled so that key rotation at the IdP cannot lock users out or leave stale keys trusted, and set server.oauthbearer_authentication.issuers.custom_ca rather than disabling TLS verification when the IdP uses a private CA.
  4. Require verified TLS on clients: Bearer tokens are credentials. cockroach sql enforces sslmode=verify-full; configure other clients the same way.
  5. Maintain backup authentication: Keep a password or certificate for administrative users so that an IdP outage does not lock you out. root cannot use OAUTHBEARER.
  6. Review provisioned users and synchronized roles: Audit SHOW USERS WITH SOURCE regularly, and remember that group-based authorization synchronizes every matching role, including admin.
  7. Tokens are not stored: CockroachDB validates each token in memory and does not persist it. Keep token lifetimes short at the IdP.

See also