This project supports optional bearer-token authentication for provider endpoints:
/tool/tool/*/sse/messages/mcp/mcp/*/api/api/*/ui/help/doc-set/v1/opampAuthentication mode is controlled by provider config keys in opamp.json. Static token and JWT
validation settings are provided by environment variables.
For production-facing deployments fronted by an API gateway, including internal-vs-external client profiles and route policy guidance, see:
Both provider auth config keys use the same values:
none (default): no bearer checks.config-token: compare bearer token against a configured static secret.idp: validate JWT bearer tokens using JWKS (for example Keycloak).Provider config key provider.opamp-use-authorization controls /v1/opamp HTTP and WebSocket:
none (default): no bearer validation on OpAMP transport.config-token: require Authorization: Bearer <token> and compare with OPAMP_AUTH_STATIC_TOKEN.idp: require bearer token and validate JWT using OPAMP_AUTH_JWT_*.Provider config key provider.ui-use-authorization controls non-OpAMP HTTP and MCP transport
routes (including websocket scopes), for example /tool, /sse, /messages, /mcp, /api,
/ui, /help, /doc-set:
none (default): no bearer validation.config-token: require Authorization: Bearer <token> and compare with UI_AUTH_STATIC_TOKEN.idp: require bearer token and validate JWT using UI_AUTH_JWT_*.OpAMP transport env vars:
| Variable | Purpose | Default |
|---|---|---|
OPAMP_AUTH_STATIC_TOKEN |
Shared secret token used when provider.opamp-use-authorization=config-token |
unset |
OPAMP_AUTH_JWT_ISSUER |
JWT issuer URL (claim validation; also used to derive JWKS URL) | unset |
OPAMP_AUTH_JWT_AUDIENCE |
Required aud claim in OpAMP idp mode |
unset |
OPAMP_AUTH_JWT_JWKS_URL |
Explicit JWKS URL (overrides issuer-derived JWKS endpoint) | derived from issuer |
OPAMP_AUTH_JWT_LEEWAY_SECONDS |
JWT time-claim leeway | 30 |
OPAMP_AUTH_IDP_LOGIN_URL |
Optional explicit IdP login URL | derived from issuer |
OPAMP_AUTH_IDP_CLIENT_ID |
Optional client id for derived IdP login URL | unset |
UI/API/MCP env vars:
| Variable | Purpose | Default |
|---|---|---|
UI_AUTH_STATIC_TOKEN |
Shared secret token used when provider.ui-use-authorization=config-token |
unset |
UI_AUTH_JWT_ISSUER |
JWT issuer URL (claim validation; also used to derive JWKS URL) | unset |
UI_AUTH_JWT_AUDIENCE |
Required aud claim in non-OpAMP idp mode |
unset |
UI_AUTH_JWT_JWKS_URL |
Explicit JWKS URL (overrides issuer-derived JWKS endpoint) | derived from issuer |
UI_AUTH_JWT_LEEWAY_SECONDS |
JWT time-claim leeway | 30 |
UI_AUTH_IDP_LOGIN_URL |
Optional explicit IdP login URL | derived from issuer |
UI_AUTH_IDP_CLIENT_ID |
Optional client id for derived IdP login URL | unset |
For local endpoint development and unit tests:
{
"provider": {
"opamp-use-authorization": "none",
"ui-use-authorization": "none"
}
}
Use static mode for lightweight dev/staging auth without an IdP.
# /v1/opamp endpoints
export OPAMP_AUTH_STATIC_TOKEN='replace-with-long-random-token'
# non-OpAMP HTTP + MCP endpoints
export UI_AUTH_STATIC_TOKEN='replace-with-long-random-token'
Example request:
curl -H "Authorization: Bearer ${UI_AUTH_STATIC_TOKEN}" http://127.0.0.1:8080/tool
Use the helper script to create/configure a local Keycloak container, realm, client, and test user:
./scripts/configure_keycloak.sh
Windows (cmd):
scripts\configure_keycloak.cmd
Windows (PowerShell):
.\scripts\configure_keycloak.ps1
Prepare container only (no realm/client/user changes):
./scripts/configure_keycloak.sh --ready-only
scripts\configure_keycloak.cmd --ready-only
.\scripts\configure_keycloak.ps1 -ReadyOnly
Force Podman runtime:
CONTAINER_RUNTIME=podman ./scripts/configure_keycloak.sh --ready-only
set CONTAINER_RUNTIME=podman && scripts\configure_keycloak.cmd --ready-only
$env:CONTAINER_RUNTIME='podman'; .\scripts\configure_keycloak.ps1 -ReadyOnly
The script prints:
Configure provider JWT auth:
# /v1/opamp endpoints
export OPAMP_AUTH_JWT_ISSUER='http://127.0.0.1:8081/realms/opamp'
export OPAMP_AUTH_JWT_AUDIENCE='opamp-mcp'
# non-OpAMP HTTP + MCP endpoints
export UI_AUTH_JWT_ISSUER='http://127.0.0.1:8081/realms/opamp'
export UI_AUTH_JWT_AUDIENCE='opamp-ui'
Request a bearer token from Keycloak:
TOKEN="$(
curl -s -X POST \
http://127.0.0.1:8081/realms/opamp/protocol/openid-connect/token \
-d grant_type=password \
-d client_id=opamp-mcp \
-d client_secret=opamp-mcp-secret \
-d username=opamp-user \
-d password=opamp-password \
| python3 -c 'import json,sys; print(json.load(sys.stdin)["access_token"])'
)"
Use the token:
curl -H "Authorization: Bearer ${TOKEN}" http://127.0.0.1:8080/tool/commands
When your MCP client supports custom headers, pass:
Authorization: Bearer <token>
at connection/request time for /sse, /messages, or /mcp transports.
For MCP client setup script usage and command-line parameters (Claude/Codex/canonical),
see ../mcp/README.md.
If auth is enabled and no valid bearer token is provided, provider returns 401.
Any rejected authorization attempt is logged at warning level with:
This is intended for operational visibility and troubleshooting.