Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions documentation/changelog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,40 @@ description: Recent updates and improvements to the QuestDB documentation.

This page tracks significant updates to the QuestDB documentation.

## October 2026

### New

- [Microsoft Entra ID](/docs/security/oidc/entra-id/) - New page for Microsoft Entra ID: the Web Console sign-in guide, moved from the OIDC page, and app-only tokens for Azure managed identities and service principals in QuestDB Enterprise 4.0.2, with an app role and a QuestDB group for each service, how to keep app roles the only way in, how to cut off one service, and Python examples that ingest and renew the token, also with store-and-forward on disk
- [Where QuestDB reads the user information](/docs/security/oidc/#where-questdb-reads-the-user-information) - Compares the User Info endpoint with reading the claims from the token: which token each client sends, what QuestDB checks, and when a change to the groups takes effect
- [User and group claims](/docs/security/oidc/#user-and-group-claims) - How QuestDB Enterprise 4.0.2 reads the principal and the groups from the user information: fallback claim lists, how to order them so that user tokens keep their groups, the rules for missing, `null`, and empty claims, how to choose the principal claim, and the startup checks
- [Token validation](/docs/security/oidc/#token-validation), [Troubleshooting OIDC logins](/docs/security/oidc/#troubleshooting-oidc-logins), and [Versions before 4.0.2](/docs/security/oidc/#versions-before-402) - What QuestDB checks in a token, including that it does not check the audience of a token that it sends to the User Info endpoint, how long it accepts a token after it expires, the log messages of rejected logins, how earlier versions differ, and what to check when you upgrade
- [Tables created by external users](/docs/security/oidc/#tables-created-by-external-users) - Ingestion fails when it has to create a table or add a column for a user who logs in through OIDC, so create the tables in advance, or create them with SQL and `OWNED BY`, naming one of the user's QuestDB groups
- [Group changes, sessions, and revoking access](/docs/security/oidc/#group-changes-sessions-and-revoking-access) - When a change in the identity provider takes effect, that open connections and the HTTP session of the Web Console keep the groups of the last token that QuestDB accepted, that the Web Console logs out a disabled user only when the provider issued it a refresh token, and how to cut off access immediately
- [Token lifetime](/docs/security/oidc/#token-lifetime) - How QuestDB treats the token of a client as it expires, and how to switch a long-running client to a new token before then without losing the rows that QuestDB has not acknowledged

### Reference

- [`acl.oidc.groups.claim`](/docs/configuration/oidc/#acloidcgroupsclaim) and [`acl.oidc.sub.claim`](/docs/configuration/oidc/#acloidcsubclaim) - Documented the comma-separated fallback claim lists of QuestDB Enterprise 4.0.2 and the startup validation. `acl.oidc.groups.claim` is now listed with no default, as it must be set when OIDC is enabled. Username and password (ROPC) logins take the principal from the username that the client sends
- [`acl.oidc.pkce.required`](/docs/configuration/oidc/#acloidcpkcerequired) - Corrected the property name, previously documented as `acl.oidc.pkce.enabled`, which QuestDB does not recognize
- [`acl.oidc.groups.encoded.in.token`](/docs/configuration/oidc/#acloidcgroupsencodedintoken) - Documented that QuestDB Enterprise 4.0.2 rejects expired tokens and tokens without an `exp` claim, which earlier versions accept, and which token QuestDB reads the principal and the groups from
- [`acl.oidc.audience`](/docs/configuration/oidc/#acloidcaudience) and [`acl.oidc.cache.ttl`](/docs/configuration/oidc/#acloidccachettl) - Documented that `acl.oidc.audience` takes a single value, which the `aud` claim of a token must be or contain, and that QuestDB does not use it with the User Info endpoint, and what the cache holds when the groups are encoded in the token or a user logs in with a username and password
- [`acl.oidc.public.keys.expiry`](/docs/configuration/oidc/#acloidcpublickeysexpiry) and [`acl.oidc.state.required`](/docs/configuration/oidc/#acloidcstaterequired) - Documented how long QuestDB uses the signing keys of the OIDC provider before it downloads them again, and the `state` check of the Web Console login
- [`acl.oidc.configuration.url`](/docs/configuration/oidc/#acloidcconfigurationurl) and [`acl.oidc.host`](/docs/configuration/oidc/#acloidchost) - Documented that QuestDB downloads the discovery document at startup and does not start without it, that with `acl.oidc.host` QuestDB starts while the provider is unreachable, and that the two settings cannot be combined

### Updated

- [OpenID Connect (OIDC)](/docs/security/oidc/) - The identity provider guides moved to their own pages, under OpenID Connect (OIDC) in the sidebar, the introduction lists what the page covers, and [Configuration options](/docs/security/oidc/#configuration-options), right after the introduction, shows a minimal configuration
- [PingFederate](/docs/security/oidc/pingfederate/) - Moved from the OIDC page to its own page, and added the [QuestDB configuration](/docs/security/oidc/pingfederate/#questdb-configuration). Corrected the directory that PingFederate reads the users from over LDAP: Microsoft Entra Domain Services or an Active Directory domain, as Microsoft Entra ID has no LDAP endpoint
- [OIDC for the PGWire endpoint](/docs/security/oidc/#oidc-for-the-pgwire-endpoint) - Documented which token to send in the password field, that QuestDB takes the principal and the groups from the token, and that the connection should use TLS
- [Mapping user permissions](/docs/security/oidc/#mapping-user-permissions) - Corrected what happens when the groups claim is missing or empty: QuestDB rejects the login. A user is authenticated without permissions only when none of their groups is mapped to a QuestDB group. Added the endpoint permission that each interface needs, and how external aliases match
- [Find user information](/docs/security/oidc/#8-find-user-information) and [non-interactive clients](/docs/security/oidc/#non-interactive-clients) - Corrected which token of a user reaches QuestDB with `acl.oidc.groups.encoded.in.token=true`: the ID token rather than the access token. Non-interactive clients also covers the tokens that services obtain for themselves, with client credentials and password grant examples over QWP
- [Endpoint permissions](/docs/security/rbac/#endpoint-permissions) - The `HTTP` permission also covers QWP over WebSocket. The [authentication methods](/docs/security/rbac/#authentication) and [users and service accounts](/docs/security/rbac/#users-and-service-accounts) describe external users, who log in through OIDC
- [Microsoft Entra ID guide](/docs/security/oidc/entra-id/#web-console-sign-in) - Uses `preferred_username` as the principal claim instead of the display name, explains when to use `oid` instead, and registers the application as single-tenant
- [Python client](/docs/connect/clients/python/#authentication-and-tls) - Corrected when bad credentials raise: by default, `connect()` opens its first connections and raises, and `lazy_connect=on` defers the error to the first operation. Corrected that a terminal server rejection, such as a missing grant, raises `QuestDBServerRejectionError` from `flush(wait=True)`, as described in [Flushing and acknowledgements](/docs/connect/clients/python/#flushing-and-acknowledgements), and that with `sf_dir` the rejected rows stay on disk and are sent again before later batches, as described in [Server rejections](/docs/connect/clients/python/#server-rejections)
- [C/C++](/docs/connect/clients/c-and-cpp/#connecting) and [Rust](/docs/connect/clients/rust/#connecting) clients - Corrected when connection and authentication errors surface: by default, the pool connects when it is created and the errors surface there, and `lazy_connect=on` defers them
- [Python](/docs/connect/clients/python/), [C/C++](/docs/connect/clients/c-and-cpp/), [.NET](/docs/connect/clients/dotnet/), and [Go](/docs/connect/clients/go/) clients - Corrected token rotation: build a new client with a new token before the old token expires, then close the old one once QuestDB has acknowledged what it sent, or close the old one first when it uses `sf_dir`

## September 2026

### QuestDB Enterprise Releases
Expand Down
164 changes: 144 additions & 20 deletions documentation/configuration/oidc.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: OpenID Connect (OIDC)
description: Configuration settings for OpenID Connect integration in QuestDB Enterprise.
description: "Configure OIDC in QuestDB Enterprise: provider endpoints, TLS, PKCE, ROPC, token audience, and principal and groups claims with fallback lists."
---

:::note
Expand All @@ -26,6 +26,16 @@ For detailed information about OIDC, see the
OAuth2 audience as set on the tokens issued by the OIDC Provider. Defaults
to the client ID if not set.

With `acl.oidc.groups.encoded.in.token=true`, QuestDB accepts a token only when
its `aud` claim is this value, or a list that contains it. The setting takes a
single value. Keep the default: the ID tokens that the Web Console sends carry
the client ID, so another value makes Web Console logins fail. See
[Token validation](/docs/security/oidc/#token-validation).

With `acl.oidc.groups.encoded.in.token=false`, QuestDB does not use this
setting: it accepts any access token that the provider's User Info endpoint
accepts, whatever its audience.

### acl.oidc.client.id

- **Default**: none
Expand All @@ -42,6 +52,15 @@ enabled.
URL where the OpenID Provider's configuration information can be loaded in
JSON format. Should always end with `/.well-known/openid-configuration`.

QuestDB downloads the document when it starts, and takes the provider's
endpoints from it. QuestDB does not start when it cannot download or parse the
document. The error starts with
`Unable to download OIDC provider configuration from` or
`Unable to parse OIDC provider configuration`. To let QuestDB start while the
provider is unreachable, set [`acl.oidc.host`](#acloidchost) and the
[endpoint settings](#endpoints) instead. QuestDB refuses to start when both
this setting and `acl.oidc.host` are set.

### acl.oidc.enabled

- **Default**: `false`
Expand All @@ -55,8 +74,11 @@ configuration options must also be set.
- **Default**: none
- **Reloadable**: no

OIDC provider hostname. Required when OIDC is enabled, unless the OIDC
configuration URL is set.
OIDC provider hostname. Required when OIDC is enabled, unless
[`acl.oidc.configuration.url`](#acloidcconfigurationurl) is set. The two
settings cannot be combined: QuestDB refuses to start when both are set. With
`acl.oidc.host`, QuestDB starts even when the provider is unreachable, and only
OIDC logins fail until the provider is reachable again.

### acl.oidc.http.timeout

Expand Down Expand Up @@ -89,6 +111,14 @@ location where it was loaded from (`window.location.href`).
The OIDC server asks consent for the scopes listed in this property. The
scope `openid` is mandatory and must always be included.

The Web Console requests these scopes when the user logs in. Add
`offline_access` if the provider issues a refresh token only for that scope,
such as Microsoft Entra ID. Without a refresh token, the Web Console cannot
renew its tokens, and does not log the user out when the user is disabled in
the provider. See
[Credentials received](/docs/security/oidc/#6-credentials-received) in the
OIDC guide.

## Authentication flows

### acl.oidc.pg.token.as.password.enabled
Expand All @@ -100,13 +130,19 @@ When enabled, the PGWire endpoint supports OIDC authentication. The OAuth2
token should be sent in the password field, while the username field should
contain the string `_sso`, or left empty if that is an option.

### acl.oidc.pkce.enabled
### acl.oidc.pkce.required

- **Default**: `true`
- **Reloadable**: no

Enables or disables PKCE for the Authorization Code Flow. This should always
be enabled in production. The Web Console is not fully secure without it.
Whether the Web Console uses PKCE (Proof Key for Code Exchange) in the
Authorization Code Flow. This should always be enabled in production. The Web
Console is not fully secure without it.

`acl.oidc.pkce.enabled` is not a QuestDB setting. QuestDB reports it as an
invalid setting at startup and does not apply its value, and with
[`config.validation.strict=true`](/docs/configuration/overview/#configvalidationstrict)
it refuses to start. Use `acl.oidc.pkce.required` instead.

### acl.oidc.ropc.flow.enabled

Expand All @@ -116,6 +152,17 @@ be enabled in production. The Web Console is not fully secure without it.
Enables or disables the Resource Owner Password Credentials flow. When
enabled, this flow must also be configured in the OIDC Provider.

### acl.oidc.state.required

- **Default**: `false`
- **Reloadable**: no

Whether the Web Console sends a random `state` parameter in the authorization
request of the Authorization Code Flow, and rejects the redirect back from the
OIDC Provider when it does not carry the same `state`. This ties the redirect
to a login that the same browser started, which protects against cross-site
request forgery on the login redirect.

## Endpoints

### acl.oidc.authorization.endpoint
Expand All @@ -132,8 +179,20 @@ Identity Platform.
- **Reloadable**: no

JSON Web Key Set (JWKS) Endpoint. Provides the list of public keys used to
decode and validate ID tokens issued by the OIDC Provider. The default value
should work for the Ping Identity Platform.
decode and validate the tokens issued by the OIDC Provider, such as ID tokens,
when `acl.oidc.groups.encoded.in.token` is `true`. The default value should
work for the Ping Identity Platform.

### acl.oidc.public.keys.expiry

- **Default**: `120000`
- **Reloadable**: no

How long QuestDB uses the public keys that it downloaded from the JWKS
endpoint, in milliseconds, before it downloads them again. QuestDB also
downloads the keys again when a token names a key ID that it does not know,
such as a key that the OIDC Provider has just started to use. See
[Troubleshooting OIDC logins](/docs/security/oidc/#troubleshooting-oidc-logins).

### acl.oidc.token.endpoint

Expand Down Expand Up @@ -196,37 +255,102 @@ which it connects.

## User and group claims

QuestDB reads the principal and the group memberships of an external user from
the user information: the User Info endpoint's response or, when
`acl.oidc.groups.encoded.in.token` is `true`, the payload of a JWT, such as an
ID token. `acl.oidc.sub.claim` and `acl.oidc.groups.claim` each take a single
claim name or, since QuestDB Enterprise 4.0.2, a comma-separated list of claim
names in priority order. For how QuestDB picks the claims, with examples, see
[User and group claims](/docs/security/oidc/#user-and-group-claims) in the
OIDC guide. For how versions before 4.0.2 differ, see
[Versions before 4.0.2](/docs/security/oidc/#versions-before-402).

### acl.oidc.cache.ttl

- **Default**: `30000`
- **Reloadable**: no

User info cache entry TTL in milliseconds. QuestDB caches user info responses
for each valid access token. This setting controls how often the access token
is validated and user info refreshed.
How long QuestDB caches the user information of a valid token, in
milliseconds: the User Info endpoint's response or, when
`acl.oidc.groups.encoded.in.token` is `true`, the result of validating the
token. This setting controls how often a token is validated again and the user
information refreshed. With `acl.oidc.groups.encoded.in.token=true`, the user
information comes from the token itself, so a change to it takes effect when
the client presents a new token. For username and password logins through the
ROPC flow, QuestDB caches the result of the login for this long, then requests
a new token from the provider, so with either setting, changes take effect
after this time.

### acl.oidc.groups.claim

- **Default**: `groups`
- **Default**: none
- **Reloadable**: no

The name of the custom claim in the user information that contains the
group memberships of the user.
The claim in the user information that contains the group memberships of the
user, as an array of group names or as a single group name. Required when OIDC
is enabled.

Since QuestDB Enterprise 4.0.2, accepts a comma-separated list of claims in
priority order, in the form `claimName[,claimName ...]`, such as
`roles,groups`. Spaces around claim names are trimmed, and empty entries are
skipped. QuestDB takes the groups from the first claim on the list that holds
at least one group name, and does not combine groups from several claims. A login is rejected when none of the listed claims
holds a group name. With OIDC enabled, QuestDB refuses to start when the list
names a claim twice, or names a claim that `acl.oidc.sub.claim` also lists.

On earlier versions, a list makes every OIDC login fail. With
`acl.oidc.groups.encoded.in.token=true`, earlier versions also require a
`groups` array in the token, whatever this setting names.

See [How QuestDB picks a claim](/docs/security/oidc/#how-questdb-picks-a-claim)
and [Startup validation](/docs/security/oidc/#startup-validation).

### acl.oidc.groups.encoded.in.token

- **Default**: `false`
- **Reloadable**: no

When `true`, QuestDB looks for group memberships in the ID token instead of
calling the User Info endpoint. Set to `true` if the OIDC Provider encodes
group memberships directly into the token.
When `true`, QuestDB reads the principal and the group memberships from a JWT
instead of calling the User Info endpoint: the ID token, which the Web Console
sends and QuestDB obtains itself in the ROPC flow, or a token that a client
presents, such as an Entra ID app-only access token. QuestDB validates the
token itself, as described in
[Token validation](/docs/security/oidc/#token-validation). Set to `true` if the
OIDC Provider encodes group memberships directly into the token.

Since QuestDB Enterprise 4.0.2, QuestDB also rejects expired tokens and tokens
without an `exp` claim. Earlier versions do not check the `exp` claim of the
token.

### acl.oidc.sub.claim

- **Default**: `sub`
- **Reloadable**: no

The name of the claim in the user information that contains the user's name.
Could be a username, full name, or email. Displayed in the Web Console and
logged for audit purposes.
The claim in the user information that contains the user's principal, such as
a username, an email address, or an object ID. Displayed in the Web Console,
returned by `current_user()`, and logged for audit purposes. Pick a claim that
identifies one user or service, and that the provider never gives to anyone
else: QuestDB keeps one external user per principal and replaces its groups at
every login, so users who share a principal share permissions. Avoid display
names, such as the `name` claim. See
[Choose the principal claim](/docs/security/oidc/#choose-the-principal-claim).

For username and password logins through the ROPC flow, the principal is the
username that the client sends instead. QuestDB still requires one of the
listed claims to carry a value, but does not use that value.

Since QuestDB Enterprise 4.0.2, accepts a comma-separated list of claims in
priority order, in the form `claimName[,claimName ...]`, such as
`preferred_username,oid`. Spaces around claim names are trimmed, and empty
entries are skipped. QuestDB takes the principal from the first claim on the
list that holds a non-empty value. A login is
rejected when none of the listed claims holds one. With OIDC enabled, QuestDB
refuses to start when the value is empty, when the list names a claim twice, or
when it names a claim that `acl.oidc.groups.claim` also lists. An empty value
does not fall back to the default `sub`.

On earlier versions, a list makes every OIDC login fail.

See [How QuestDB picks a claim](/docs/security/oidc/#how-questdb-picks-a-claim)
and [Startup validation](/docs/security/oidc/#startup-validation).
Loading
Loading