Configuring Apicurio Registry security options
This chapter explains how to set configuration options for Apicurio Registry security. For example, this includes authentication in Keycloak, Microsoft Azure Active Directory, or Dex, and role-based authorization in Apicurio Registry.
-
Configuring Apicurio Registry authentication and authorization with Keycloak
-
Configuring Apicurio Registry authentication and authorization with Microsoft Azure Active Directory
-
Configuring Apicurio Registry authentication and authorization with Dex
-
Apicurio Registry authentication and authorization configuration options
-
Configuring Apicurio Registry Cross-Origin Resource Sharing (CORS)
| For a list of all available configuration options, see Apicurio Registry configuration reference. |
Configuring Apicurio Registry authentication and authorization with Keycloak
This section explains how to manually configure authentication and authorization options for Apicurio Registry and Keycloak.
|
Alternatively, for details on how to configure these settings automatically, see the Apicurio Registry Operator documentation. |
The Apicurio Registry web console and core REST API support authentication in Keycloak based on OAuth and OpenID Connect (OIDC). The same Keycloak realm and users are federated across the Apicurio Registry web console and core REST API using OpenID Connect so that you only require one set of credentials.
Apicurio Registry provides role-based authorization for default admin, write, and read-only user roles. Apicurio Registry provides content-based authorization at the schema or API level, where only the creator of the registry artifact can update or delete it. Apicurio Registry authentication and authorization settings are disabled by default.
-
Keycloak is installed and running. For more details, see the Keycloak user documentation.
-
Apicurio Registry is installed and running.
-
In the Keycloak Admin Console, create a Keycloak realm for Apicurio Registry. By default, Apicurio Registry expects a realm name of
registry. For details on creating realms, see the Keycloak user documentation. -
Create a Keycloak client for the Apicurio Registry API. By default, Apicurio Registry expects the following settings:
-
Client ID:
registry-api -
Client Protocol:
openid-connect -
Access Type:
bearer-onlyYou can use the defaults for the other client settings.
If you are using Keycloak service accounts, the client Access Type must be confidentialinstead ofbearer-only.
-
-
Create a Keycloak client for the Apicurio Registry web console. By default, Apicurio Registry expects the following settings:
-
Client ID:
apicurio-registry -
Client Protocol:
openid-connect -
Access Type:
public -
Valid Redirect URLs:
http://my-registry-url:8080/* -
Web Origins:
+You can use the defaults for the other client settings.
-
-
In your Apicurio Registry deployment on OpenShift, set the following Apicurio Registry environment variables to configure authentication using Keycloak:
Table 1. Configuration for Apicurio Registry authentication with Keycloak Environment variable Description Type Default QUARKUS_OIDC_TENANT_ENABLEDEnables authentication for Apicurio Registry. When set to
true, the environment variables that follow are required for authentication using Keycloak.String
falseQUARKUS_OIDC_AUTH_SERVER_URLThe URL of the Keycloak authentication server. For example,
http://localhost:8080.String
-
QUARKUS_OIDC_CLIENT_IDThe client ID for the Apicurio Registry REST API.
String
registry-apiAPICURIO_UI_AUTH_OIDC_CLIENT_IDThe client ID for the Apicurio Registry web console.
String
apicurio-registryFor an example of setting environment variables on OpenShift, see [configuring-liveness-readiness-probes_registry]. -
Set the following option to
trueto enable Apicurio Registry user roles in Keycloak:Table 2. Configuration for Apicurio Registry role-based authorization Environment variable Java system property Type Default value APICURIO_AUTH_ROLE_BASED_AUTHORIZATIONapicurio.auth.role-based-authorizationBoolean
false -
When Apicurio Registry user roles are enabled, you must assign Apicurio Registry users to at least one of the following default user roles in your Keycloak realm:
Table 3. Default user roles for registry authentication and authorization Role Read artifacts Write artifacts Global rules Summary sr-adminYes
Yes
Yes
Full access to all create, read, update, and delete operations.
sr-developerYes
Yes
No
Access to create, read, update, and delete operations, except configuring global rules. This role can configure artifact-specific rules.
sr-readonlyYes
No
No
Access to read and search operations only. This role cannot configure any rules.
-
Set the following to
trueto enable owner-only authorization for updates to schema and API artifacts in Apicurio Registry:Table 4. Configuration for owner-only authorization Environment variable Java system property Type Default value APICURIO_AUTH_OWNER_ONLY_AUTHORIZATION_LIMIT_GROUP_ACCESSapicurio.auth.owner-only-authorization.limit-group-accessBoolean
false
-
For details on configuring non-default user role names, see Apicurio Registry authentication and authorization configuration options.
-
For an open source example application and Keycloak realm, see Docker Compose example of Apicurio Registry with Keycloak.
-
For details on how to use Keycloak in a production environment, see the Keycloak documentation.
Configuring Apicurio Registry authentication and authorization with Microsoft Azure Active Directory
This section explains how to manually configure authentication and authorization options for Apicurio Registry and Microsoft Azure Active Directory (Azure AD).
The Apicurio Registry web console and core REST API support authentication in Azure AD based on OpenID Connect (OIDC) and the OAuth Authorization Code Flow. Apicurio Registry provides role-based authorization for default admin, write, and read-only user roles. Apicurio Registry authentication and authorization settings are disabled by default.
To secure Apicurio Registry with Azure AD, you require a valid directory in Azure AD with specific configuration. This involves registering the Apicurio Registry application in the Azure AD portal with recommended settings and configuring environment variables in Apicurio Registry.
-
Azure AD is installed and running. For more details, see the Microsoft Azure AD user documentation.
-
Apicurio Registry is installed and running.
-
Log in to the Azure AD portal using your email address or GitHub account.
-
In the navigation menu, select Manage > App registrations > New registration, and complete the following settings:
-
Name: Enter your application name. For example:
apicurio-registry-example -
Supported account types: Click Accounts in any organizational directory.
-
Redirect URI: Select Single-page application from the list, and enter your Apicurio Registry web console application host. For example:
https://test-registry.com/ui/You must register your Apicurio Registry application host as a Redirect URI. When logging in, users are redirected from Apicurio Registry to Azure AD for authentication, and you want to send them back to your application afterwards. Azure AD does not allow any redirect URLs that are not registered.
-
-
Click Register. You can view your app registration details by selecting Manage > App registrations > apicurio-registry-example.
-
Select Manage > Authentication and ensure that the application is configured with your redirect URLs and tokens as follows:
-
Redirect URIs: For example:
https://test-registry.com/ui/ -
Implicit grant and hybrid flows: Click ID tokens (used for implicit and hybrid flows)
-
-
Select Azure AD > Admin > App registrations > Your app > Application (client) ID. For example:
123456a7-b8c9-012d-e3f4-5fg67h8i901 -
Select Azure AD > Admin > App registrations > Your app > Directory (tenant) ID. For example:
https://login.microsoftonline.com/1a2bc34d-567e-89f1-g0hi-1j2kl3m4no56/v2.0 -
In Apicurio Registry, configure the following environment variables with your Azure AD settings:
Table 5. Configuration for Azure AD settings in Apicurio Registry Environment variable Description Setting QUARKUS_OIDC_CLIENT_IDThe client application ID for the Apicurio Registry REST API
Your Azure AD Application (client) ID obtained in step 5. For example:
123456a7-b8c9-012d-e3f4-5fg67h8i901APICURIO_UI_AUTH_OIDC_CLIENT_IDThe client application ID for the Apicurio Registry web console.
Your Azure AD Application (client) ID obtained in step 5. For example:
123456a7-b8c9-012d-e3f4-5fg67h8i901QUARKUS_OIDC_AUTH_SERVER_URLThe URL for authentication in Azure AD.
Your Azure AD Application (tenant) ID obtained in step 6. For example:
https://login.microsoftonline.com/1a2bc34d-567e-89f1-g0hi-1j2kl3m4no56/v2.0. -
In Apicurio Registry, configure the following environment variables for Apicurio Registry-specific settings:
Table 6. Configuration for Apicurio Registry-specific settings Environment variable Description Setting QUARKUS_OIDC_TENANT_ENABLEDEnables authentication for Apicurio Registry.
trueQUARKUS_HTTP_CORS_ORIGINSThe host for your Apicurio Registry deployment for cross-origin resource sharing (CORS).
For example:
https://test-registry.comAPICURIO_UI_AUTH_OIDC_REDIRECT_URIThe host for your Apicurio Registry web console.
For example:
https://test-registry.com/uiAPICURIO_AUTH_ROLE_BASED_AUTHORIZATIONEnables role-based authorization in Apicurio Registry.
trueQUARKUS_OIDC_ROLES_ROLE_CLAIM_PATHThe name of the claim in which Azure AD stores roles.
rolesWhen you enable roles in Apicurio Registry, you must also create the same roles in Azure AD as application roles. The default roles expected by Apicurio Registry are sr-admin,sr-developer, andsr-readonly. -
In Apicurio Registry UI, configure the following environment variables:
| Environment variable | Description | Setting |
|---|---|---|
|
|
|
|
Which token to use. Azure AD has non-standard access tokens, so we need to use id tokens. |
|
Multiple role mappings for Azure Entra ID
When using Azure Entra ID (formerly Azure AD), you may need to map multiple Azure AD groups or app roles to a single Apicurio Registry role. This is useful when:
-
Interactive users authenticate via Azure AD groups
-
Service principals authenticate via app roles
-
Both should grant the same Apicurio Registry permissions
To configure multiple role mappings, use comma-separated values:
# Map multiple Azure AD groups/roles to registry roles
APICURIO_AUTH_ROLES_ADMIN=sr-admin,12345678-aaaa-bbbb-cccc-ddddeeeefffff,AppRole.Admin
APICURIO_AUTH_ROLES_DEVELOPER=sr-developer,87654321-aaaa-bbbb-cccc-ddddeeeefffff,AppRole.Developer
APICURIO_AUTH_ROLES_READONLY=sr-readonly,abcd1234-aaaa-bbbb-cccc-ddddeeeefffff,AppRole.Reader
With this configuration, a user with any of the listed roles or group memberships will be granted the corresponding Apicurio Registry authorization level.
Client-specific OAuth scopes for Azure Entra ID
Azure Entra ID requires that each app registration uses a unique scope. When you have multiple app registrations (for example, one for developers and one for read-only access), you can configure client-specific scopes:
# Default scope for all clients (fallback)
APICURIO_AUTHN_BASIC_SCOPE=api://default-app-id/.default
# Client-specific scope overrides
# Replace dots in client IDs with underscores for environment variables
APICURIO_AUTHN_BASIC_SCOPE_SR_DEVELOPER_CLIENT=api://developer-app-id/.default
APICURIO_AUTHN_BASIC_SCOPE_SR_READONLY_CLIENT=api://readonly-app-id/.default
When a client authenticates, Apicurio Registry will:
-
Check for a client-specific scope configuration matching the client ID
-
If not found, use the default scope
-
If no scope is configured, proceed without a scope parameter
| Multiple scopes can be specified using comma separation. They will be converted to space-separated format per the OAuth2 specification. |
-
For details on configuring non-default user role names, see Apicurio Registry authentication and authorization configuration options.
-
For more details on using Azure AD, see the Microsoft Azure AD user documentation.
Configuring Apicurio Registry authentication and authorization with Dex
This section explains how to configure authentication and authorization for Apicurio Registry by using Dex as a federated OpenID Connect (OIDC) identity provider.
Dex acts as an OIDC-compliant bridge in front of identity providers that do not fully implement the OIDC specification. This is useful when your platform uses an OAuth server that does not expose standard OIDC endpoints, such as OpenShift’s built-in OAuth server, LDAP directories, or SAML-based providers. Dex has connectors for 15+ identity providers including OpenShift, LDAP, SAML, GitHub, GitLab, Google, and Microsoft.
Without an OIDC-compliant provider, the following Apicurio Registry features do not work:
| Feature | Without OIDC bridge | Why it breaks |
|---|---|---|
UI login flow |
Not available |
The Apicurio Registry web console uses |
Principal identity |
Not available |
The username cannot be extracted because it may be nested in a non-standard location in the token. Apicurio Registry expects flat top-level claims. |
Owner-based authorization |
Not available |
Depends on principal identity, which is empty when the provider does not expose standard claims. |
By deploying Dex between Apicurio Registry and your identity provider, all three features work because Dex exposes standard OIDC discovery, issues JWTs with standard claims (sub, name, email, groups), and provides a standard JWKS endpoint.
-
A Kubernetes cluster with Helm 3.x installed.
-
Apicurio Registry is installed and running.
-
Access to the upstream identity provider you want to integrate (for example, OpenShift, LDAP, or GitHub).
-
Deploy Dex on your cluster by using Helm:
helm repo add dex https://charts.dexidp.io helm repo update {kubernetes-client} create namespace dex -
Create a Helm values file named
dex-values.yamlwith the following content. Replace the placeholder values with your actual configuration.Apicurio Registry needs two OAuth clients: a public client for the browser-based UI (which cannot hold a secret) and a confidential client for the backend and CLI. You must also configure
allowedOriginsso the UI can fetch the Dex OIDC discovery endpoint via CORS.config: issuer: https://dex.<cluster-domain> storage: type: kubernetes config: inCluster: true web: http: 0.0.0.0:5556 # CORS: Required so the Apicurio UI (oidc-client-ts) can fetch # /.well-known/openid-configuration from a different origin. allowedOrigins: - "https://<registry-ui-route>" oauth2: skipApprovalScreen: true responseTypes: [code, token, id_token] # Two clients are needed: # - A PUBLIC client for the browser UI (oidc-client-ts cannot hold secrets) # - A CONFIDENTIAL client for CLI/API token exchange staticClients: - id: apicurio-registry-ui name: Apicurio Registry UI public: true redirectURIs: - "https://<registry-ui-route>/" - "https://<registry-ui-route>/dashboard" - id: apicurio-registry name: Apicurio Registry API secret: <GENERATE_A_SECURE_SECRET> redirectURIs: - "https://<registry-ui-route>/" - "https://<registry-app-route>/" connectors: [] # Configure in the next step ingress: enabled: true hosts: - host: dex.<cluster-domain> paths: - path: / pathType: PrefixThe UI client must be public: truebecause the browser-based authorization code flow with PKCE cannot securely store a client secret. If you use a single confidential client for both UI and backend, the UI login will fail withinvalid_clienterrors. The/dashboardredirect URI is needed because the Apicurio Registry UI redirects there after login.When generating the client secret, avoid special characters such as +,/, or=that may cause URL encoding mismatches. Useopenssl rand -base64 32 | tr -d '+/=' | head -c 32to generate a safe secret.On OpenShift, create a Route instead of using Ingress:
oc create route edge dex --service=dex --port=5556 --hostname=dex.<cluster-domain> --namespace=dex -
Install Dex by using Helm:
helm install dex dex/dex -n dex -f dex-values.yaml -
Verify that OIDC discovery is available:
curl -sk https://dex.<cluster-domain>/.well-known/openid-configuration | jq .issuer # Expected: "https://dex.<cluster-domain>" -
Configure a connector for your upstream identity provider. Add the connector configuration to the
connectorssection in yourdex-values.yamlfile. See Dex connector examples for configuration examples. -
After updating the connector configuration, upgrade the Dex Helm release:
helm upgrade dex dex/dex -n dex -f dex-values.yaml -
In your Apicurio Registry deployment, set the following environment variables to configure authentication using Dex:
Table 8. Configuration for Apicurio Registry authentication with Dex Environment variable Description Type Default QUARKUS_OIDC_TENANT_ENABLEDEnables authentication for Apicurio Registry. When set to
true, the environment variables that follow are required.String
falseQUARKUS_OIDC_AUTH_SERVER_URLThe URL of the Dex OIDC server. For example,
https://dex.example.com.String
-
QUARKUS_OIDC_CLIENT_IDThe client ID for the Apicurio Registry REST API. Must match the public client ID (
apicurio-registry-ui) so the backend accepts tokens issued by Dex for the UI.String
registry-apiAPICURIO_UI_AUTH_OIDC_CLIENT_IDThe client ID for the Apicurio Registry web console. Must match the public Dex static client.
String
apicurio-registryQUARKUS_OIDC_AUTHENTICATION_SCOPESThe OIDC scopes to request. Must include
groupsso that Dex includes group membership in the token.String
openidQUARKUS_OIDC_ROLES_ROLE_CLAIM_PATHThe JWT claim path where roles are stored. Dex passes upstream group membership in the
groupsclaim.String
-
QUARKUS_OIDC_TOKEN_PRINCIPAL_CLAIMThe JWT claim to use as the principal identity for artifact ownership. Set to
emailbecause Dex populates this as a flat top-level claim.String
subAPICURIO_UI_AUTH_OIDC_SCOPEThe OIDC scopes requested by the Apicurio Registry web console. Must include
groupsso that the UI token contains group membership for role-based authorization.String
openid profile emailFor example, when using Dex, set these values:
QUARKUS_OIDC_TENANT_ENABLED=true QUARKUS_OIDC_AUTH_SERVER_URL=https://dex.example.com QUARKUS_OIDC_CLIENT_ID=apicurio-registry-ui APICURIO_UI_AUTH_OIDC_CLIENT_ID=apicurio-registry-ui QUARKUS_OIDC_AUTHENTICATION_SCOPES=openid,email,profile,groups QUARKUS_OIDC_ROLES_ROLE_CLAIM_PATH=groups QUARKUS_OIDC_TOKEN_PRINCIPAL_CLAIM=email APICURIO_UI_AUTH_OIDC_SCOPE=openid profile email groupsBoth QUARKUS_OIDC_CLIENT_IDandAPICURIO_UI_AUTH_OIDC_CLIENT_IDmust be set to the public client ID (apicurio-registry-ui). If they do not match, the backend will reject tokens issued for a different audience withInvalidJwtSignatureExceptionerrors. -
Configure role-based authorization. Dex passes upstream group membership in the
groupsclaim. Map your upstream groups to Apicurio Registry roles:Table 9. Configuration for Apicurio Registry role-based authorization with Dex Environment variable Description Type Default APICURIO_AUTH_ROLE_BASED_AUTHORIZATIONEnables role-based authorization in Apicurio Registry.
Boolean
falseAPICURIO_AUTH_ROLE_SOURCEWhere to get user roles. Set to
tokento read from the JWT.String
tokenAPICURIO_AUTH_ROLES_ADMINThe upstream group name that grants admin access.
String
sr-adminAPICURIO_AUTH_ROLES_DEVELOPERThe upstream group name that grants developer access.
String
sr-developerAPICURIO_AUTH_ROLES_READONLYThe upstream group name that grants read-only access.
String
sr-readonlyThe mapping between upstream provider groups and Apicurio Registry roles works as follows:
Table 10. Group-to-role mapping example Upstream group Dex passes as CR role config Apicurio Registry role registry-adminsregistry-adminsadmin: registry-adminsAdmin
registry-developersregistry-developersdeveloper: registry-developersDeveloper
registry-readersregistry-readersreadOnly: registry-readersRead-Only
-
Enable owner-based authorization. Because Dex provides proper principal identity through the
emailclaim, owner-based authorization works correctly:APICURIO_AUTH_OWNER_ONLY_AUTHORIZATION=trueWith this setting, only the user who created an artifact can modify or delete it. For more details on owner-only authorization, see Apicurio Registry owner-only authorization.
-
If you are using the Apicurio Registry Operator on Kubernetes, you can configure all of the above in the
ApicurioRegistry3custom resource. Thespec.app.authsection covers the standard OIDC settings, and Dex-specific properties must be set usingspec.app.env. Usespec.app.ingresswith TLS annotations instead of the barehostfield:apiVersion: registry.apicur.io/v1 kind: ApicurioRegistry3 metadata: name: apicurio-registry namespace: apicurio-registry spec: app: ingress: host: apicurio-registry-app-apicurio-registry.apps.<cluster-domain> # On OpenShift, this annotation enables edge TLS termination on the Route, # so the app is served over HTTPS with automatic HTTP -> HTTPS redirect. annotations: route.openshift.io/termination: edge auth: enabled: true # Both must point to the PUBLIC Dex client so the backend accepts # tokens with aud=apicurio-registry-ui issued by the browser flow. appClientId: apicurio-registry-ui uiClientId: apicurio-registry-ui authServerUrl: "https://dex.<cluster-domain>" # Explicit redirect URI prevents oidc-client-ts from using the current # page URL (which may contain stale ?code=...&state=... query params), # fixing silent token refresh failures. redirectUri: "https://<registry-ui-route>/" anonymousReadsEnabled: true tls: tlsVerificationType: "none" authz: enabled: true readAccessEnabled: true ownerOnlyEnabled: true groupAccessEnabled: false roles: source: token admin: "registry-admins" developer: "registry-developers" readOnly: "registry-readers" adminOverride: enabled: true from: token type: role role: "registry-admins" env: - name: QUARKUS_OIDC_AUTHENTICATION_SCOPES value: "openid,email,profile,groups" - name: QUARKUS_OIDC_ROLES_ROLE_CLAIM_PATH value: "groups" - name: QUARKUS_OIDC_TOKEN_PRINCIPAL_CLAIM value: "email" # The UI scope defaults to "openid profile email" which does NOT include # groups. Without this, Dex won't include group membership in the token # and RBAC will deny all write operations. - name: APICURIO_UI_AUTH_OIDC_SCOPE value: "openid profile email groups" ui: ingress: host: apicurio-registry-ui-apicurio-registry.apps.<cluster-domain> annotations: route.openshift.io/termination: edge env: # The operator hardcodes http:// for REGISTRY_API_URL. # Override it to use HTTPS since we enabled edge TLS on the app route. - name: REGISTRY_API_URL value: "https://apicurio-registry-app-apicurio-registry.apps.<cluster-domain>/apis/registry/v3"There are a few important details in this CR:
Two-client architecture — Both
appClientIdanduiClientIdare set toapicurio-registry-ui(the public Dex client). The browser-based UI usesoidc-client-ts, which cannot securely hold a client secret. If you use a confidential client for the UI, the token exchange will fail withInvalid client credentials. The backend validates JWT signatures via the JWKS endpoint and does not need a client secret. The separate confidential client (apicurio-registry) is kept for CLI/API token exchange via curl or scripts.UI scope with
groups— TheAPICURIO_UI_AUTH_OIDC_SCOPEenv var addsgroupsto the scope the UI requests from Dex. Without this, the default scope (openid profile email) does not include groups, and Dex will not put group membership in the token. RBAC then denies all write operations because it cannot determine the user’s role. This has been verified on a live cluster with Dex v2.45.1 and the OpenShift connector: tokens include thegroupsclaim with the user’s OpenShift group memberships, and Apicurio Registry successfully resolves roles for RBAC authorization.Explicit
redirectUri— Without this,oidc-client-tsuseswindow.location.hrefas the redirect URI for silent token refresh. After the initial login, the URL may still contain?code=…&state=…query parameters, which do not match any registered redirect URI in Dex, causing a 400 error.A complete example CR is available in the Dex example CR. -
Verify that all features work correctly:
# Verify OIDC discovery curl -sk https://dex.<cluster-domain>/.well-known/openid-configuration | jq .issuer # Verify anonymous read access (if enabled) curl -sk https://<registry-app-route>/apis/registry/v3/system/info # Verify UI login — open in browser and authenticate via your upstream provider # https://<registry-ui-route> # Verify principal identity — artifacts should have an owner curl -sk https://<registry-app-route>/apis/registry/v3/groups/my-group \ -H "Authorization: Bearer $TOKEN" | jq .owner # Expected: the user's email address, NOT empty
Dex connector examples
Dex supports many upstream identity providers via pluggable connectors. The following examples show how to configure the most common connectors.
OpenShift connector
First, create an OAuthClient for Dex on your OpenShift cluster:
CLIENT_SECRET=$(openssl rand -base64 32 | tr -d '=' | head -c 32)
cat <<EOF | oc apply -f -
apiVersion: oauth.openshift.io/v1
kind: OAuthClient
metadata:
name: dex
grantMethod: auto
secret: "$CLIENT_SECRET"
redirectURIs:
- "https://dex.<cluster-domain>/callback"
EOF
Then add the connector to your dex-values.yaml:
connectors:
- type: openshift
id: openshift
name: OpenShift
config:
issuer: https://api.<cluster-domain>:6443
clientID: dex
clientSecret: "<CLIENT_SECRET>"
redirectURI: https://dex.<cluster-domain>/callback
groups:
- registry-admins
- registry-developers
- registry-readers
insecureCA: true # Set to false in production and configure proper CA
LDAP connector
connectors:
- type: ldap
id: ldap
name: LDAP
config:
host: ldap.example.com:636
bindDN: cn=admin,dc=example,dc=com
bindPW: <bind-password>
userSearch:
baseDN: ou=users,dc=example,dc=com
filter: "(objectClass=person)"
username: uid
idAttr: uid
emailAttr: mail
nameAttr: cn
groupSearch:
baseDN: ou=groups,dc=example,dc=com
filter: "(objectClass=groupOfNames)"
userMatchers:
- userAttr: DN
groupAttr: member
nameAttr: cn
GitHub connector
connectors:
- type: github
id: github
name: GitHub
config:
clientID: <github-oauth-app-client-id>
clientSecret: <github-oauth-app-client-secret>
redirectURI: https://dex.<cluster-domain>/callback
orgs:
- name: your-organization
teams:
- registry-admins
- registry-developers
Microsoft Azure AD connector
connectors:
- type: microsoft
id: microsoft
name: Microsoft
config:
clientID: <azure-app-client-id>
clientSecret: <azure-app-client-secret>
redirectURI: https://dex.<cluster-domain>/callback
tenant: <azure-tenant-id>
groups:
- <registry-admins-group-uuid>
- <registry-developers-group-uuid>
SAML 2.0 connector
connectors:
- type: saml
id: saml
name: Corporate SSO
config:
ssoURL: https://idp.example.com/sso
ca: /etc/dex/saml-ca.crt
redirectURI: https://dex.<cluster-domain>/callback
usernameAttr: name
emailAttr: email
groupsAttr: groups
| Dex supports using multiple connectors simultaneously. This enables federation across multiple identity providers, allowing users from different organizations or systems to authenticate to Apicurio Registry through a single Dex instance. |
Machine-to-machine (M2M) access and Kafka SerDes
The configuration above covers the browser-based UI flow. For CI/CD pipelines, Kafka SerDes, and services that need to interact with the Apicurio Registry API without a browser, additional considerations apply.
Dex client_credentials support (unreleased as of v2.45.1)
Dex added client_credentials support via PR #4583 (merged March 3, 2026), but this feature is not included in Dex v2.45.1 — the latest stable release at time of writing. It will ship in v2.46.0 or later.
To test before a stable release, use the dexidp/dex:master image from Docker Hub (rebuilt daily by Dex CI). For production, wait for v2.46.0+.
|
Enable it by setting an environment variable on the Dex deployment:
# In the Dex Deployment spec (requires Dex master or >= v2.46.0)
env:
- name: DEX_CLIENT_CREDENTIAL_GRANT_ENABLED_BY_DEFAULT
value: "true"
Then use the confidential client to obtain a token:
TOKEN_RESPONSE=$(curl -s -X POST "https://dex.<cluster-domain>/token" \
--data-urlencode "grant_type=client_credentials" \
--data-urlencode "client_id=apicurio-registry" \
--data-urlencode "client_secret=<CLIENT_SECRET>" \
--data-urlencode "scope=openid profile")
ACCESS_TOKEN=$(echo $TOKEN_RESPONSE | jq -r .access_token)
Even with client_credentials working, the tokens do not include the groups claim. The groups scope is accepted but no groups are populated because there is no upstream connector or user in the client_credentials flow — the token is built solely from the static client definition, which has no group membership. Since Apicurio Registry uses groups for RBAC, M2M clients authenticating via client_credentials will have no assigned role.
|
| Scenario | Works? | Why |
|---|---|---|
SerDes reading schemas (with |
Yes |
Anonymous reads bypass authentication entirely. |
SerDes registering schemas |
No |
No role in token means write access is denied. |
CI/CD creating artifacts |
No |
No role in token means write access is denied. |
Recommended approach for Kafka SerDes
For the most common Kafka use case — consumers fetching schemas — you do not need client_credentials at all. Set anonymousReadsEnabled: true in the Apicurio Registry CR and the SerDes can read schemas without any token. This is the recommended approach for read-heavy workloads.
For schema registration (typically done by developers or CI/CD, not by Kafka producers at runtime), use the authorization code flow with the confidential client and a service user that has the right groups.
Upcoming fix: groups on static clients
The lack of groups in client_credentials tokens has been reported in dexidp/dex#4690, and a fix has been submitted in dexidp/dex#4691. The fix adds a clientCredentialsClaims sub-struct to static client definitions, keeping identity attributes separate from core client fields:
staticClients:
- id: apicurio-registry
secret: "..."
clientCredentialsClaims:
groups: ["registry-admins"] # included in client_credentials tokens
Track the PR for when this lands in a stable Dex release.
When to use Keycloak instead
If your deployment requires M2M write access with proper RBAC — for example, if Kafka producers register schemas at runtime, or if you have many CI/CD pipelines that need different permission levels — use Keycloak (or Auth0, Azure AD) instead of Dex. These providers support service account roles natively, so client_credentials tokens include all the claims Apicurio Registry needs.
Dex is the right choice when:
-
Your upstream IdP is non-OIDC-compliant (OpenShift OAuth, LDAP, SAML)
-
You primarily need user-facing auth (UI login, principal identity, owner-based authz)
-
M2M workloads are read-only (SerDes consumers with anonymous reads)
Dex production considerations
When running Dex in production, consider the following:
-
TLS: Configure Dex with proper TLS via Ingress termination or its own certificate. In the Apicurio Registry CR, set
spec.app.auth.tls.tlsVerificationTypetocertificateand provide a truststore if using a private CA. -
High availability: Run multiple Dex replicas. For better HA, switch Dex’s storage backend from Kubernetes CRDs to PostgreSQL.
-
Network policies: Restrict access so that only Apicurio Registry pods and the ingress controller can reach Dex. Ensure Dex can reach your upstream identity providers.
-
Secret management: Store the Dex client secret securely using Kubernetes Secrets or a secrets manager such as HashiCorp Vault.
Dex troubleshooting
-
"Invalid client credentials" on UI login: The UI (
oidc-client-ts) runs in the browser and cannot send a client secret. Use a public Dex client (public: true, no secret) for the UI. A confidential client will always fail. -
403 Forbidden on API calls after UI login: Two common causes: (1) Audience mismatch — the UI gets tokens with
aud: "apicurio-registry-ui"but the backend expectsaud: "apicurio-registry". Fix: set bothappClientIdanduiClientIdto the same public client ID. (2) Missinggroupsscope — the default UI scope does not includegroups. Fix: setAPICURIO_UI_AUTH_OIDC_SCOPEtoopenid profile email groups. -
Groups not appearing in the token: Verify that both
QUARKUS_OIDC_AUTHENTICATION_SCOPES(backend) andAPICURIO_UI_AUTH_OIDC_SCOPE(UI) includegroups. Decode the JWT to inspect:echo $TOKEN | cut -d. -f2 | base64 -d | jq . -
"Unregistered redirect_uri" on page refresh: The UI redirects to
/dashboardafter login. Addhttps://<registry-ui-route>/dashboardto the Dex client’s redirect URIs. -
Silent token refresh returns 400:
oidc-client-tsuses the current page URL (with stale?code=…&state=…params) as the redirect URI. Fix: setredirectUriexplicitly in the Apicurio Registry CR auth config. -
"No end session endpoint" on logout: Dex does not implement OIDC RP-Initiated Logout. The local session is still cleared, but
signoutRedirectfails. This is a known Dex limitation — the error is non-blocking. -
CORS errors in browser console: The UI cannot fetch
/.well-known/openid-configurationfrom Dex. Add the UI route origin toweb.allowedOriginsin the Dex config. -
InvalidJwtSignatureExceptionafter Dex restart: Dex generates new signing keys on restart. Old tokens become invalid. Users must re-authenticate. For production, configure persistent signing keys. -
invalid_clientwhen exchanging authorization code: If the client secret contains special characters (+,/,=), use--data-urlencodeinstead of-din curl. -
Owner field is empty: Check that
QUARKUS_OIDC_TOKEN_PRINCIPAL_CLAIMis set to a claim that Dex populates, such asemail,name, orsub. -
UI redirects to Dex but gets an error: Check Dex logs (
kubectl logs -n dex deploy/dex). This is usually a redirect URI mismatch or connector misconfiguration. -
client_credentialsreturnsunsupported_grant_type: This grant type was added in Dex PR #4583 (merged March 3, 2026) but is not included in v2.45.1 or earlier. You need Dex >= v2.46.0 or a build frommaster. -
"OIDC Server is not available": The Apicurio Registry pod cannot reach Dex. Check DNS resolution, network policies, and TLS trust configuration.
-
For details on configuring non-default user role names, see Apicurio Registry authentication and authorization configuration options.
-
For a complete list of supported connectors, see the Dex connectors documentation.
-
For details on Dex deployment and configuration, see the Dex documentation.
Apicurio Registry authentication and authorization configuration options
Apicurio Registry provides authentication options for OpenID Connect with Keycloak and HTTP basic authentication.
Apicurio Registry provides authorization options for role-based and content-based approaches:
-
Role-based authorization for default admin, write, and read-only user roles.
-
Content-based authorization for schema or API artifacts, where only the owner of the artifacts or artifact group can update or delete artifacts.
All authentication and authorization options in Apicurio Registry are disabled by default. Before enabling any of these options, you must first set the QUARKUS_OIDC_TENANT_ENABLED option to true.
|
This chapter provides details on the following configuration options:
Apicurio Registry authentication by using OpenID Connect with Keycloak
You can set the following environment variables to configure authentication for the Apicurio Registry web console and API with Keycloak:
| Environment variable | Description | Type | Default |
|---|---|---|---|
|
Enables authentication for Apicurio Registry. When set to |
String |
|
|
The URL of the Keycloak authentication server. For example, |
String |
- |
|
The client ID for the Apicurio Registry REST API. |
String |
|
|
The client ID for the Apicurio Registry web console. |
String |
|
|
Specifies the file path to the TLS trust store used by Quarkus for securing OpenID Connect (OIDC) communications. The trust store can be populated with the trusted certificates needed to establish secure TLS connections with the OIDC provider. |
String |
- |
|
The password required to access the TLS trust store file. |
String |
- |
|
Enables or disables role-based authorization. |
Boolean |
False |
Apicurio Registry authentication by using HTTP basic
By default, Apicurio Registry supports authentication by using OpenID Connect. Users or API clients must obtain an access token to make authenticated calls to the Apicurio Registry REST API. However, because some tools do not support OpenID Connect, you can also configure Apicurio Registry to support HTTP basic authentication by setting the following configuration options to true:
| Environment variable | Java system property | Type | Default value |
|---|---|---|---|
|
|
Boolean |
|
|
|
Boolean |
|
Apicurio Registry HTTP basic client credentials cache expiry
You can also configure the HTTP basic client credentials cache expiry time. By default, when using HTTP basic authentication, Apicurio Registry caches JWT tokens, and does not issue a new token when there is no need. You can configure the cache expiry time for JWT tokens, which is set to 10 mins by default.
When using Keycloak, it is best to set this configuration to your Keycloak JWT expiry time minus one minute. For example, if you have the expiry time set to 5 mins in Keycloak, you should set the following configuration option to 4 mins:
| Environment variable | Java system property | Type | Default value |
|---|---|---|---|
|
|
Integer |
|
Apicurio Registry role-based authorization
You can set the following options to true to enable role-based authorization in Apicurio Registry:
| Environment variable | Java system property | Type | Default value |
|---|---|---|---|
|
|
Boolean |
|
|
|
Boolean |
|
You can then configure role-based authorization to use roles included in the user’s authentication token (for example, granted when authenticating by using Keycloak), or to use role mappings managed internally by Apicurio Registry.
Use roles assigned in Keycloak
To enable using roles assigned by Keycloak, set the following environment variables:
| Environment variable | Description | Type | Default |
|---|---|---|---|
|
When set to |
String |
|
|
The name of the role that indicates a user is an admin. |
String |
|
|
The name of the role that indicates a user is a developer. |
String |
|
|
The name of the role that indicates a user has read-only access. |
String |
|
When Apicurio Registry is configured to use roles from Keycloak, you must assign Apicurio Registry users to at least one of the following user roles in Keycloak. However, you can configure different user role names by using the environment variables in Configuration for Apicurio Registry role-based authorization by using Keycloak.
| Role name | Read artifacts | Write artifacts | Global rules | Description |
|---|---|---|---|---|
|
Yes |
Yes |
Yes |
Full access to all create, read, update, and delete operations. |
|
Yes |
Yes |
No |
Access to create, read, update, and delete operations, except configuring global rules and import/export. This role can configure artifact-specific rules only. |
|
Yes |
No |
No |
Access to read and search operations only. This role cannot configure any rules. |
Manage roles directly in Apicurio Registry
To enable using roles managed internally by Apicurio Registry, set the following environment variable:
| Environment variable | Description | Type | Default |
|---|---|---|---|
|
When set to |
String |
|
When using internally managed role mappings, users can be assigned a role by using the /admin/roleMappings
endpoint in the Apicurio Registry REST API. For more details, see Apicurio Registry REST API documentation.
Users can be granted exactly one role: ADMIN, DEVELOPER, or READ_ONLY. Only users with admin
privileges can grant access to other users.
Apicurio Registry admin-override configuration
Because there are no default admin users in Apicurio Registry, it is usually helpful to configure another way for users to be identified as admins. You can configure this admin-override feature by using the following environment variables:
| Environment variable | Description | Type | Default |
|---|---|---|---|
|
Enables the admin-override feature. |
String |
|
|
Where to look for admin-override information. Only |
String |
|
|
The type of information used to determine if a user is an admin. Values depend on the value of the FROM variable, for example, |
String |
|
|
The name of the role that indicates a user is an admin. |
String |
|
|
The name of a JWT token claim to use for determining admin-override. |
String |
|
|
The value that the JWT token claim indicated by the CLAIM variable must be for the user to be granted admin-override. |
String |
|
For example, you can use this admin-override feature to assign the sr-admin role to a single user
in Keycloak, which grants that user the admin role. That user can then use the /admin/roleMappings
REST API (or associated UI) to grant roles to additional users (including additional admins).
Apicurio Registry owner-only authorization
You can set the following options to true to enable owner-only authorization for updates to artifacts or artifact groups in Apicurio Registry:
| Environment variable | Java system property | Type | Default value |
|---|---|---|---|
|
|
Boolean |
|
|
|
Boolean |
|
|
|
Boolean |
|
When owner-only authorization is enabled, only the user who created an artifact can modify or delete that artifact.
When owner-only authorization and group owner-only authorization are both enabled, only the user who created an artifact group has write access to that artifact group, for example, to add or remove artifacts in that group.
Apicurio Registry authenticated read access
When the authenticated read access option is enabled, Apicurio Registry grants at least read-only access to requests from any authenticated user in the same organization, regardless of their user role.
To enable authenticated read access, you must first enable role-based authorization, and then ensure that the following options are set to true:
| Environment variable | Java system property | Type | Default value |
|---|---|---|---|
|
|
Boolean |
|
|
|
Boolean |
|
For more details, see Apicurio Registry role-based authorization.
Apicurio Registry anonymous read-only access
In addition to the two main types of authorization (role-based and owner-based authorization), Apicurio Registry supports an anonymous read-only access option.
To allow anonymous users, such as REST API calls with no authentication credentials, to make read-only
calls to the REST API, set the following options to true:
| Environment variable | Java system property | Type | Default value |
|---|---|---|---|
|
|
Boolean |
|
|
|
Boolean |
|
-
For an example of how to set environment variables in your Apicurio Registry deployment on OpenShift, see [configuring-liveness-readiness-probes_registry]
-
For details on configuring custom authentication for Apicurio Registry, the see Quarkus Open ID Connect documentation
Configuring Apicurio Registry Cross-Origin Resource Sharing (CORS)
Cross-Origin Resource Sharing (CORS) is a browser security feature that controls how web applications running at one origin can request resources from a different origin. Apicurio Registry includes built-in CORS support that you can configure to allow the Apicurio Registry web console or other client applications to access the Apicurio Registry REST API from different domains.
CORS configuration in Apicurio Registry is based on the underlying Quarkus HTTP CORS filter. By default, Apicurio Registry enables CORS and allows requests from http://localhost:8888 and http://127.0.0.1:8888 for local development.
-
Apicurio Registry is installed and running.
Configure the following environment variables to customize CORS behavior for your Apicurio Registry deployment:
| Environment variable | Description | Default |
|---|---|---|
|
Enables or disables the CORS filter. Set to |
|
|
A comma-separated list of allowed origins for CORS requests. Use |
|
|
A comma-separated list of HTTP methods allowed for CORS requests. |
|
|
A comma-separated list of HTTP headers allowed in CORS requests. This includes custom Apicurio Registry headers used for artifact metadata. |
See note below |
The default allowed headers include: x-registry-name, x-registry-name-encoded, x-registry-description, x-registry-description-encoded, x-registry-version, x-registry-artifactid, x-registry-artifacttype, x-registry-hash-algorithm, x-registry-content-hash, access-control-request-method, access-control-allow-credentials, access-control-allow-origin, access-control-allow-headers, authorization, content-type, content-encoding, user-agent.
|
environment:
QUARKUS_HTTP_CORS_ORIGINS: "*"
Using * to allow all origins is not recommended for production deployments. Always specify explicit allowed origins in production environments.
|
environment:
QUARKUS_HTTP_CORS_ORIGINS: "https://registry-ui.example.com,https://admin.example.com"
If you are using the Apicurio Registry Operator, you can configure CORS in the ApicurioRegistry3 custom resource:
apiVersion: registry.apicur.io/v1
kind: ApicurioRegistry3
metadata:
name: my-registry
spec:
app:
env:
- name: QUARKUS_HTTP_CORS_ORIGINS
value: https://ui.example.com
When using the Apicurio Registry Operator with an Ingress configured for the UI component, the operator automatically configures CORS allowed origins based on the Ingress host. If you explicitly set QUARKUS_HTTP_CORS_ORIGINS in the CR, your configuration takes precedence.
|
-
For detailed information about all available Quarkus CORS configuration options, see the Quarkus HTTP Reference - CORS Filter documentation.
