Integrate OIDC for Access Control
ScalarDB Cluster supports OpenID Connect (OIDC) access control based on JWT access tokens as an alternative to password-based authentication. By using JWT access tokens from an OIDC provider (for example, Keycloak), client applications can authenticate requests without managing ScalarDB passwords directly. When combined with ABAC, claims in the JWT access token can dynamically restrict per-request access based on attributes embedded in the token.
How the OIDC integration works
This section describes the key concepts behind the OIDC integration in ScalarDB Cluster.
Use case
The OIDC integration is designed for scenarios where one or more OIDC users map to a single ScalarDB service user. The OIDC client application authenticates users through the OIDC provider, obtains a JWT access token containing the ScalarDB username and access scope, and sends the token with each request to ScalarDB Cluster.
ScalarDB Cluster processes requests within the permissions of the mapped ScalarDB user, further restricted by the JWT claims.
Authentication flow
When a client sends a request with a JWT access token, ScalarDB Cluster performs the following steps:
- Fetches the OIDC provider configuration. ScalarDB Cluster retrieves the OpenID Provider Configuration from
{issuer_url}/.well-known/openid-configurationand caches the result. - Fetches the JWKS. ScalarDB Cluster extracts the JWKS (JSON Web Key Set) URL from the provider configuration, fetches the keys, and caches them.
- Validates the JWT. ScalarDB Cluster verifies the token signature and standard claims per RFC 9068.
- Maps the token to a ScalarDB user. ScalarDB Cluster extracts the ScalarDB username from the configured claim and looks up the user record.
- Validates the authentication method. ScalarDB Cluster confirms that the user is permitted to use OIDC authentication and that the issuer is trusted.
- Applies ABAC restrictions when enabled. If the OIDC ABAC integration is enabled, the JWT must contain an ABAC claim. ScalarDB Cluster calculates the ABAC user tag for the session and applies it. Tokens without the ABAC claim are rejected.
- Executes the request. ScalarDB Cluster executes the request as the mapped ScalarDB user with the applicable restrictions.
JWT access token validation
ScalarDB Cluster validates JWT access tokens following RFC 9068. Specifically, the following checks are performed:
typheader: By default, thetypheader must beat+jwtorapplication/at+jwt. You can disable this check by settingrequire_at_jwt_typtofalse.- Signature: The token signature is verified by using the keys from the OIDC provider's JWKS endpoint. Only the following algorithms are accepted: RSASSA-PKCS-v1_5, RSASSA-PSS, and ECDSA.
issclaim: The issuer must match the value configured intrusted_issuers.audclaim: The audience must contain the value configured inaudience.name.expclaim: The token must not be expired. A configurable clock skew tolerance is applied.
User mapping
ScalarDB Cluster identifies the ScalarDB user by extracting the value of the claim specified in username.claim_name from the validated JWT. ScalarDB uses this value to look up the corresponding user record in the users metadata table.
Choose the username claim carefully. Unintentionally or incorrectly sharing a ScalarDB user across OIDC users may cause a security issue.
Per-user authentication method
Each ScalarDB user has an authentication_methods attribute that specifies which authentication methods are permitted for that user. When a user is created with the AUTH_METHOD OIDC option, OIDC authentication is enabled for that user.
The following restrictions apply to OIDC users:
- Superusers cannot use OIDC. If the mapped ScalarDB user is a superuser, the OIDC authentication request is rejected for security reasons.
- The issuer must be trusted. The
issclaim in the JWT must match the value in thetrusted_issuersconfiguration.
Dynamic ABAC restriction
When the OIDC ABAC integration is enabled, ScalarDB Cluster reads the ABAC claim (default name: scalardb_abac) from the JWT and uses it to dynamically restrict the user's access for the current request. The ABAC claim can only restrict (never expand) the permissions of the mapped ScalarDB user.
If the ABAC claim is present but exceeds the ScalarDB user's permissions, the request is rejected. If the OIDC ABAC integration is enabled and the ABAC claim is absent from the JWT, the request is also rejected.
For details about the claim structure and validation rules, see JWT ABAC claim reference.
Configurations
This section describes the configurations for the OIDC integration. For general authentication and authorization configurations, see Authenticate and Authorize Users.
Server-side configurations
For server-side OIDC configurations, see OIDC configurations in the ScalarDB Cluster configurations.
In addition to the OIDC-specific properties, you must also enable authentication and authorization by setting scalar.db.cluster.auth.enabled to true. If you use ABAC, you must also set scalar.db.cluster.abac.enabled to true.
Client-side configurations
For client-side OIDC configurations, see the Java Client SDK configurations in the ScalarDB Cluster configurations for both the primitive interface and the SQL interface.
When you use oidc_jwt, the scalar.db.username and scalar.db.password properties are not required. You can pass the JWT access token programmatically by using OidcJwtAccessTokenHolder, which is the recommended option when handling many OIDC users. Alternatively, you can supply the token via a property (for example, scalar.db.sql.cluster_mode.auth.oidc_jwt.access_token), which is easy to start with, especially for testing with tools like the SQL CLI. However, since the token is set at initialization time, it cannot be refreshed.
Tutorial - Integrate OIDC with ABAC for dynamic access control
This tutorial demonstrates how to set up OIDC authentication with ABAC dynamic access control by using Keycloak as the OIDC provider. You will set up ScalarDB Cluster, configure ABAC policies, set up Keycloak, and verify the integration by using both curl and the Java client.
Prerequisites
- OpenJDK LTS version (8, 11, 17, or 21) from Eclipse Temurin
- Docker 20.10 or later with Docker Compose V2 or later
jqfor JSON processing
This tutorial has been tested with OpenJDK from Eclipse Temurin. ScalarDB itself, however, has been tested with JDK distributions from various vendors. For details about the requirements for ScalarDB, including compatible JDK distributions, please see Requirements.
This tutorial uses auth.localhost as the hostname for Keycloak. On macOS and Linux, *.localhost subdomains automatically resolve to 127.0.0.1 per RFC 6761. If name resolution does not work in your environment (some Windows configurations or certain browsers like Firefox), add the following entry to your hosts file (/etc/hosts on macOS/Linux or C:\Windows\System32\drivers\etc\hosts on Windows):
127.0.0.1 auth.localhost
You need to have a license key (trial license or commercial license) to use ScalarDB Cluster. If you don't have a license key, please contact us.
1. Create the ScalarDB Cluster configuration file
Create the following configuration file as scalardb-cluster-node.properties, replacing <YOUR_LICENSE_KEY> and <LICENSE_CHECK_CERT_PEM> with your ScalarDB license key and license check certificate values. For more information about the license key and certificate, see How to Configure a Product License Key.
scalar.db.storage=jdbc
scalar.db.contact_points=jdbc:postgresql://postgresql:5432/postgres
scalar.db.username=postgres
scalar.db.password=postgres
scalar.db.cluster.node.standalone_mode.enabled=true
scalar.db.sql.enabled=true
# Enable cross-partition scan to perform a full scan by using the SELECT statements in this tutorial.
# This is not required for OIDC or ABAC itself.
scalar.db.cross_partition_scan.enabled=true
scalar.db.cross_partition_scan.filtering.enabled=true
# Enable authentication and authorization
scalar.db.cluster.auth.enabled=true
# OIDC configurations
# auth.localhost resolves via RFC 6761 on the host and via the Docker network alias inside containers.
scalar.db.cluster.auth.oidc.trusted_issuers=http://auth.localhost:8080/realms/scalardb-demo
scalar.db.cluster.auth.oidc.audience.name=scalardb
scalar.db.cluster.auth.oidc.username.claim_name=scalardb_username
scalar.db.cluster.auth.oidc.jwt.access_token.require_at_jwt_typ=true
# ABAC configurations
scalar.db.cluster.abac.enabled=true
scalar.db.cluster.auth.oidc.abac.enabled=true
# License key configurations
scalar.db.cluster.node.licensing.license_key=<YOUR_LICENSE_KEY>
scalar.db.cluster.node.licensing.license_check_cert_pem=<LICENSE_CHECK_CERT_PEM>