Authentication & authorization
Karapace supports two authentication systems for the Schema Registry: HTTP basic auth (file-based users and access rules) and OAuth2 / OIDC (bearer token validation). The REST proxy forwards OAuth2 tokens to Kafka and the Schema Registry rather than validating them itself.
Each can be used on its own, or both at once — when both are enabled the Schema
Registry routes each request by its Authorization scheme. See
Using OIDC and basic auth together.
HTTP basic authentication
Set registry_authfile to the path of a JSON file that lists authorized users and
access-control rules. When set, the Schema Registry requires authentication for most
endpoints and applies per-endpoint authorization rules. The file is hot-reloaded, so
edits take effect without a restart.
Each user entry contains:
| Field | Description |
|---|---|
username | The user name. |
algorithm | One of scrypt, sha1, sha256, or sha512. |
salt | Salt used for hashing the password. |
password_hash | The password hash computed with the given algorithm and salt. |
Generate an entry with the karapace_mkpasswd tool (or python -m karapace.core.auth).
It prints a ready-to-use JSON user entry:
karapace_mkpasswd -u user -a sha512 secret
# Response:
# {
# "username": "user",
# "algorithm": "sha512",
# "salt": "iuLouaExTeg9ypqTxqP-dw",
# "password_hash": "R6ghYSXdLGsq6hkQcg8wT4..."
# }
Each access-control rule contains:
| Field | Description |
|---|---|
username | Matched against the authenticated user. |
operation | Read or Write. Write implies read; it covers all mutable operations, including deleting schema versions. |
resource | A regular expression matched against the accessed resource. |
Supported resources are Config: (global configuration) and Subject:<subject_name>
(where <subject_name> is a regex matched against the accessed subject).
Example authorization file
{
"users": [
{
"username": "admin",
"algorithm": "scrypt",
"salt": "<salt>",
"password_hash": "<hash>"
},
{
"username": "plainuser",
"algorithm": "sha256",
"salt": "<salt>",
"password_hash": "<hash>"
}
],
"permissions": [
{ "username": "admin", "operation": "Write", "resource": ".*" },
{
"username": "plainuser",
"operation": "Read",
"resource": "Subject:general.*"
},
{ "username": "plainuser", "operation": "Read", "resource": "Config:" }
]
}
OAuth2 / OIDC (Schema Registry)
When OAuth2 is enabled, Karapace extracts the bearer token from the Authorization
header (Authorization: Bearer $JWT) and validates it against your identity provider's
JWKS endpoint before serving the request.
sasl_oauthbearer_authentication_enabled: true
sasl_oauthbearer_jwks_endpoint_url: "https://idp.example.com/realms/karapace/protocol/openid-connect/certs"
sasl_oauthbearer_expected_issuer: "https://idp.example.com/realms/karapace"
sasl_oauthbearer_expected_audience: "account"
sasl_oauthbearer_sub_claim_name: "sub"
The token's signature, issuer, audience, expiry and the configured subject claim are all verified. Optional hardening flags:
| Flag | Default | Description |
|---|---|---|
sasl_oauthbearer_leeway_seconds | 0 | Clock-skew tolerance for exp/nbf/iat. Must be >= 0. |
sasl_oauthbearer_require_access_token_typ | false | Require the token header type to be an access-token type. |
sasl_oauthbearer_allow_insecure_jwks | false | Allow a plain-HTTP JWKS endpoint. Dev/test only — startup fails on HTTP otherwise. |
Role-based authorization
Authorization is opt-in on top of authentication. It maps HTTP methods to the roles a token must carry.
sasl_oauthbearer_authentication_enabled: true
sasl_oauthbearer_authorization_enabled: true
sasl_oauthbearer_roles_claim_path: "resource_access.karapace-client.roles"
sasl_oauthbearer_method_roles:
GET: ["karapace.schema:read", "karapace.subject:read"]
POST: ["karapace.schema:write", "karapace.subject:write"]
PUT: []
DELETE: []
sasl_oauthbearer_roles_claim_path is a dot-path into the token pointing at the list of
roles. Write the literal client id into the path.
Enabling authorization requires authentication. Enabling authorization without explicitly enabling authentication auto-enables it and logs a deprecation warning — set both flags explicitly.
Docker example
KARAPACE_SASL_OAUTHBEARER_AUTHENTICATION_ENABLED: true
KARAPACE_SASL_OAUTHBEARER_JWKS_ENDPOINT_URL: https://keycloak:8080/realms/karapace/protocol/openid-connect/certs
KARAPACE_SASL_OAUTHBEARER_EXPECTED_ISSUER: https://keycloak:8080/realms/karapace
KARAPACE_SASL_OAUTHBEARER_EXPECTED_AUDIENCE: "account"
KARAPACE_SASL_OAUTHBEARER_SUB_CLAIM_NAME: sub
Production hardening
sasl_oauthbearer_jwks_endpoint_urlmust usehttps://; startup fails otherwise./docs,/redocand/openapi.jsonbypass the auth gate by design (for Swagger UI). Block them at your reverse proxy in production to avoid exposing the API surface.
Using OIDC and basic auth together
When sasl_oauthbearer_authentication_enabled is true and registry_authfile is
set, the Schema Registry serves both systems at once and dispatches on each request's
Authorization scheme (case-insensitive). This lets clients migrate from basic auth to
OIDC one at a time — no client ever sends more than one header, and no coordinated
switch is required.
Authorization header | Handled as |
|---|---|
Bearer <jwt> | OIDC. Token is validated; invalid or expired → 401 (no fallback). Authorization uses role mapping when sasl_oauthbearer_authorization_enabled is true, otherwise a valid token is allowed. The authorization file's ACL is not consulted. |
Basic <base64> | Basic. Credentials are checked against the authorization file, and its ACL is enforced — regardless of the OIDC authorization flag. |
| missing / other | 401 |
Notes:
Bearertakes priority; there is no fallback between schemes — a bad token is never retried as basic.- With
sasl_oauthbearer_authentication_enabled: false, the OIDC gate is skipped entirely and only basic auth applies (unchanged behavior). - The REST proxy needs no extra configuration: it forwards the inbound
Authorizationheader to the Schema Registry, so bothBearerandBasicrequests work through the proxy. - The proxy's own Schema Registry credentials (
registry_user/registry_password) may be set at the same time. A forwardedAuthorizationheader always takes precedence;registry_user/registry_passwordare used only for requests that arrive without one. This lets the proxy keep a service credential as a fallback while clients migrate to forwarded tokens — the two no longer conflict. - When the Schema Registry rejects the credentials or token during a produce/consume schema
operation, the REST proxy surfaces the failure with a matching status:
401(error code401) for authentication and403(error code403) for authorization. Other schema registration failures — for example an incompatible or malformed schema — keep their own errors (40801for a registry rejection,42205for a schema that fails to parse) and are not reported as auth failures.
OAuth2 (REST proxy)
The REST proxy can pass OAuth2 credentials to the underlying Kafka service defined by
sasl_bootstrap_uri. When a bearer token is present, the Kafka clients managed by
Karapace use the SASL OAUTHBEARER mechanism and forward the token. The REST proxy does
not verify the token — Kafka validates it, and the Schema Registry validates the same
token for schema operations.
OAuth2 token forwarding depends on rest_authorization being true.
sasl_mechanism: "OAUTHBEARER"
security_protocol: "SASL_SSL"
ssl_cafile: "ca.pem"
If sasl_mechanism is PLAIN:
sasl_mechanism: "PLAIN"
security_protocol: "SASL_PLAINTEXT"
sasl_plain_username: "your_username"
sasl_plain_password: "your_password"
Token expiry
The REST proxy manages producer and consumer clients keyed by the OAuth2 token. They are cleaned up periodically when idle, and before the token expires. Before refreshing its token, a client is expected to remove its running consumers (after committing offsets) and producers that use the current token.