TKeeper authenticates & authorizes all requests to protected endpoints. The authentication mechanism is selected via the auth configuration section. Authorization is enforced using explicit permission identifiers.
Supported auth.type values
| Type | Description | Recommended use |
|---|---|---|
jwt |
Authenticate requests using JSON Web Tokens (JWT). The server verifies token signature and claims using a configured JWKS source. | Production deployments. |
dev |
Shared-token authentication for local testing. Clients send a static token and receive permissions from a dev configuration file. | Local development and isolated test environments only. |
Request headers
| Mode | Header | Value |
|---|---|---|
jwt |
X-JWT-TOKEN |
JWT access token |
dev |
X-DEV-TOKEN |
Static dev token (exact match) |
JWT authentication
When auth.type = "jwt", TKeeper validates incoming requests using a JSON Web Key Set (JWKS) configured at auth.jwt.jwks-location. The JWKS is periodically refreshed.
Validation rules
A request is authenticated only if the presented token passes all checks:
- Key selection: token header contains a
kidthat matches a key in the JWKS. - Signature verification: token signature validates under the selected key.
- Audience check: token
audincludes (or equals)auth.jwt.audience. - Subject: token has a
subclaim (used as the principal identifier in audit records).
If authentication fails, the request is rejected as unauthenticated.
Permissions source
JWT tokens MUST carry a permissions claim (string list). TKeeper uses these permission strings for authorization checks (see Authorization via permissions).
Example payload fragment:
{
"sub": "user:alice",
"aud": "tkeeper",
"permissions": [
"tkeeper.system.health",
"tkeeper.key.mykey.sign"
]
}
Configuration
auth {
type = "jwt"
jwt {
jwks-location = "https://issuer.example.com/.well-known/jwks.json"
audience = "tkeeper"
refresh = 15m
}
}
OIDC integration for the Control Plane UI
The Control Plane UI (/ui) can use an OpenID Connect (OIDC) provider to obtain a JWT for browser sessions. This is configured under auth.jwt.oidc.
OIDC properties
client-id: OIDC client identifier registered with the provider.discovery-url: provider discovery document URL (typicallyhttps://<idp>/.well-known/openid-configuration).callback-url: redirect URI on TKeeper that receives the authorization response (must match provider registration).
Configuration
auth {
type = "jwt"
jwt {
jwks-location = "https://issuer.example.com/.well-known/jwks.json"
audience = "tkeeper"
oidc {
client-id = "tkeeper-ui"
discovery-url = "https://issuer.example.com/.well-known/openid-configuration"
callback-url = "https://tkeeper.example.com/ui/oidc/callback"
}
}
}
If the OIDC section is omitted, the UI can operate in token-paste mode (manual entry of a JWT).
Dev authentication
When auth.type = "dev", TKeeper authenticates requests using a static shared token provided via X-DEV-TOKEN. Authorization permissions are loaded from DevConfig.
Warning It is intended for local development and isolated test environments only.
Requirements
To use dev authentication you must:
- Enable dev config loading
keeper.dev.enabled = true
- Provide the dev config location via JVM system property
-Dkeeper.dev.config.location=...
DevConfig is intended for local development and controlled test environments.
DevConfig format
DevConfig must define:
keeper.dev.token: token value that clients must send inX-DEV-TOKENkeeper.dev.permissions: list of permission identifiers
Example dev.conf:
keeper {
dev {
token = "dev-token-change-me"
permissions = [
"tkeeper.system.*",
"tkeeper.key.*.sign"
]
}
}
Example run:
java \
-Dkeeper.dev.enabled=true \
-Dkeeper.dev.config.location=/etc/tkeeper/dev.conf \
-Dkeeper.config.location=/etc/tkeeper/application.conf \
-jar tkeeper.jar
Authentication configuration reference
| Key | Meaning | Default / notes |
|---|---|---|
auth.type |
Authentication mechanism (jwt or dev). Can be overridden via KEEPER_AUTH_TYPE. |
dev |
auth.jwt.jwks-location |
JWKS URL or file path. Required when auth.type = "jwt". |
unset |
auth.jwt.audience |
Expected audience claim for JWT validation. Required when auth.type = "jwt". |
unset |
auth.jwt.refresh |
JWKS refresh interval. | 15m |
auth.jwt.oidc.client-id |
OIDC client id for Control Plane login. | unset |
auth.jwt.oidc.discovery-url |
OIDC discovery URL. | unset |
auth.jwt.oidc.callback-url |
Redirect URI for the OIDC flow. | unset |
DevConfig is supplied via keeper.dev.* settings in a separate dev configuration file. See Configuration for DevConfig delivery and location rules.
Authorization via permissions
Authorization is evaluated using explicit permission identifiers attached to the authenticated principal.
Wildcard Permission Matching (since 1.0.3)
TKeeper always supported * when the whole segment is a wildcard.
Starting from 1.0.3, TKeeper also supports partial wildcards inside a segment (prefix*, *suffix, prefix*suffix).
Syntax
Permissions are dot-separated segments. Each segment supports at most one * wildcard. The deep wildcard ** is explicitly forbidden to enforce least-privilege.
| Pattern | Supported in | Description | Example match |
|---|---|---|---|
exact |
all versions | Exact segment match | wallet-hot |
* |
all versions | Any single segment | wallet-hot, master |
prefix* |
>= 1.0.3 |
Segment starts with prefix | wallet-* -> wallet-hot, wallet-cold |
*suffix |
>= 1.0.3 |
Segment ends with suffix | *-hot -> wallet-hot, vault-hot |
prefix*suffix |
>= 1.0.3 |
Segment starts with prefix and ends with suffix | custody-*-prod -> custody-btc-prod |
Segment count must match exactly: tkeeper.key.*.sign does not match tkeeper.key.ns.wallet.sign.
Examples
# Grant signing with any wallet-prefixed key
tkeeper.key.wallet-*.sign
# Grant decryption with any custody key in prod
tkeeper.key.custody-*-prod.decrypt
# Grant public key retrieval for all keys
tkeeper.key.*.public
# Deny destroy on all master-prefixed keys
-tkeeper.key.master-*.destroy
Deny rules
Permissions prefixed with - act as deny rules. A permission is granted only if at least one allow pattern matches and no deny pattern matches.
# Allow signing with any key, but block master keys
tkeeper.key.*.sign
-tkeeper.key.master-*.sign
In this configuration, tkeeper.key.wallet-hot.sign is allowed, while tkeeper.key.master-root.sign is denied.
Invalid patterns
The following patterns are rejected at parse time with an error:
| Pattern | Reason |
|---|---|
** |
Deep wildcard is not allowed |
a*b*c |
Multiple wildcards per segment are not supported |
Scope patterns
Permissions are typically scoped by resource identifiers (for example key identifiers). Examples:
- Key-scoped:
tkeeper.key.<keyId>.signtkeeper.key.<keyId>.encrypt
- System-scoped:
tkeeper.system.inittkeeper.system.unseal
A caller granted tkeeper.key.mykey.sign can sign only for mykey. A caller granted tkeeper.key.*.sign can sign for all keys.
Permission sources
- JWT mode: from token claims (for example
permissions) and/or external policy enforcement in the identity provider. - Dev mode: from
keeper.dev.permissionsin DevConfig.
If permission checks fail, the request is rejected as access denied.
Permission catalog
This section lists the permission identifiers used by TKeeper.
Key-scoped permissions
Replace <logicalId> with the key logicalId.
| Permission | Description |
|---|---|
tkeeper.key.<logicalId>.public |
Retrieve public key information for a key. |
tkeeper.key.<logicalId>.sign |
Perform signing using the key. |
tkeeper.key.<logicalId>.verify |
Verify signatures using the key (where exposed as an API operation). |
tkeeper.key.<logicalId>.encrypt |
Encrypt using the key. |
tkeeper.key.<logicalId>.decrypt |
Decrypt using the key. |
tkeeper.key.<logicalId>.destroy |
Destroy the key (destructive). |
Key generation (DKG)
Replace <mode> with the key generation mode name in lowercase (create, rotate, refresh).
| Permission | Description |
|---|---|
tkeeper.dkg.<mode> |
Run Distributed Key Generation for the specified mode. |
System and platform permissions
| Permission | Description |
|---|---|
tkeeper.system.init |
Initialize the keeper system. |
tkeeper.system.seal |
Seal the system (transition into sealed state). |
tkeeper.system.unseal |
Unseal the system (transition out of sealed state). |
tkeeper.storage.write |
Import own key |
tkeeper.integrity.rotate |
Rotate the internalintegrity signing key used for audit records and request signing |
tkeeper.audit.log.verify |
Verify audit log records via verification endpoints. |
tkeeper.compliance.inventory |
Access compliance inventory endpoints. |
tkeeper.consistency.fix |
Execute consistency repair actions. |
tkeeper.control.system |
Access Control Plane system status. |
tkeeper.control.sinks |
Access Control Plane sink status. |
tkeeper.expired.view |
Fetch list of expired (or going to expire) keys in specific time-range |