You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Introduce a long-lived API key mechanism for Konveyor Hub that allows users to authenticate against Hub API services (LLM proxy, solution server/Kai, and the Hub API itself) without relying on short-lived Keycloak OIDC token rotation.
Motivation
Today, all user-facing authentication flows go through Keycloak OIDC, producing short-lived JWTs (~5 minute TTL). This works for interactive clients that can participate in the token refresh flow (e.g., the UI's Axios interceptor calls keycloak.updateToken()), but breaks for any client that receives credentials once and cannot rotate them:
CI/CD pipelines: Automated migration workflows that call the Hub API or solution server.
Third-party LLM clients: Any tool that accepts an OPENAI_API_KEY-style credential and expects it to remain valid for the session.
CLI/scripting use cases: Users interacting with Konveyor APIs from scripts or notebooks.
Current Auth Architecture
For context, the current system works as follows:
Keycloak is the sole identity provider for user-facing auth. The Hub (tackle2-hub) has a dual-provider system:
Remote (Keycloak) provider: Validates user JWTs via gocloak.DecodeAccessToken() against Keycloak's public keys. Scopes are extracted from the JWT scope claim as resource:method pairs.
Builtin provider: Issues HMAC-SHA512 signed JWTs for internal addon/task pods only. These are scoped to addon operations and tied to running task lifecycle, not suitable for user-facing API keys.
LLM proxy (llama-stack based) independently validates JWTs against the same Keycloak JWKS endpoint (/auth/realms/{realm}/protocol/openid-connect/certs) with audience konveyor-api.
Solution server (Kai) is accessed through Hub's service reverse proxy (/services/kai/*), which applies Hub's Required("kai") auth middleware, so it also relies on Keycloak JWTs.
The UI acts as a reverse proxy (Node.js Express) and is the sole external entry point. Backend services (Hub, LLM proxy, Kai) are network-isolated within the namespace.
There is no existing API key mechanism for user-facing authentication.
Goals
Users can create long-lived API keys associated with their Keycloak identity/Hub user account.
API keys inherit the RBAC scopes of the associated user (the existing tackle-admin, tackle-architect, tackle-migrator, tackle-project-manager roles and their resource:method scope mappings).
API keys are accepted as Authorization: Bearer <key> by:
The Hub API (via the existing Request.Permit() dual-provider flow)
The LLM proxy (which currently only validates Keycloak JWTs via JWKS)
The solution server/Kai (via Hub's service proxy)
API keys can be individually revoked without affecting the user's other keys or Keycloak session.
API keys can optionally have an expiration date.
The mechanism follows established patterns (GitHub PATs, OpenAI API keys) so third-party clients work with OPENAI_API_KEY=<konveyor-key> without modification.
Non-Goals
Replacing the existing Keycloak OIDC flow for interactive sessions.
Changing the network policy / ingress architecture.
Proposal
Key Lifecycle
CRUD operations for API keys: create, list, revoke/delete.
Keys are created in the context of an authenticated user (via Keycloak session or existing API key).
On creation, the plaintext key is shown once; only a hash is stored server-side.
Keys should support an optional expiration date.
Authentication Integration
The Hub already tries providers in sequence (Builtin then Keycloak). The API key mechanism could be integrated as:
A new auth provider in the chain (e.g., Builtin, then APIKey, then Keycloak), or
An extension of the existing Builtin provider
The provider would look up the key hash in the Hub database, resolve the associated user and their scopes, and return an auth.Result with the same Authenticated/Authorized/User/Scopes structure that Keycloak tokens produce.
LLM Proxy Authentication
The LLM proxy currently validates JWTs independently against Keycloak's JWKS endpoint. This means it has its own parallel auth implementation that knows nothing about Hub-issued API keys. Rather than layering workarounds (multi-issuer JWKS, token exchange, etc.), this should be addressed architecturally:
Hub as the canonical auth/RBAC authority: All Konveyor services (LLM proxy, Kai/solution server, and any future services) should delegate authentication and authorization to a single source, either Hub itself or a dedicated auth service that Hub also uses. This centralizes API key validation, RBAC enforcement, and token lifecycle management in one place rather than having each service independently validate credentials against Keycloak.
This is a broader architectural change that extends beyond API keys. It would also simplify adding new services, ensure consistent RBAC enforcement, and eliminate the current pattern of each service needing its own Keycloak JWKS integration.
The exact form this takes (Hub exposes an auth validation endpoint that services call, a sidecar/middleware pattern, or a standalone auth service) is an open design question that needs further discussion.
Storage & Security
API key hashes stored in the Hub database (the Hub already has encrypted-at-rest storage via internal/secret for Identity resources).
Keys associated with the creating user for audit and RBAC resolution.
Key metadata: name/description, creation date, last used date, expiration, scopes.
Scoping
By default, keys inherit the full scope set of the associated user's role.
Optionally, keys can be created with a reduced scope (e.g., LLM proxy access only: kai:get, kai:post).
Management Interface
Hub API endpoints for key CRUD (accessible from CLI tools and scripts).
UI support in tackle2-ui for managing keys (create, list, revoke).
Summary
Introduce a long-lived API key mechanism for Konveyor Hub that allows users to authenticate against Hub API services (LLM proxy, solution server/Kai, and the Hub API itself) without relying on short-lived Keycloak OIDC token rotation.
Motivation
Today, all user-facing authentication flows go through Keycloak OIDC, producing short-lived JWTs (~5 minute TTL). This works for interactive clients that can participate in the token refresh flow (e.g., the UI's Axios interceptor calls
keycloak.updateToken()), but breaks for any client that receives credentials once and cannot rotate them:OPENAI_API_KEY-style credential and expects it to remain valid for the session.Current Auth Architecture
For context, the current system works as follows:
Keycloak is the sole identity provider for user-facing auth. The Hub (
tackle2-hub) has a dual-provider system:Remote(Keycloak) provider: Validates user JWTs viagocloak.DecodeAccessToken()against Keycloak's public keys. Scopes are extracted from the JWTscopeclaim asresource:methodpairs.Builtinprovider: Issues HMAC-SHA512 signed JWTs for internal addon/task pods only. These are scoped to addon operations and tied to running task lifecycle, not suitable for user-facing API keys.LLM proxy (llama-stack based) independently validates JWTs against the same Keycloak JWKS endpoint (
/auth/realms/{realm}/protocol/openid-connect/certs) with audiencekonveyor-api.Solution server (Kai) is accessed through Hub's service reverse proxy (
/services/kai/*), which applies Hub'sRequired("kai")auth middleware, so it also relies on Keycloak JWTs.The UI acts as a reverse proxy (Node.js Express) and is the sole external entry point. Backend services (Hub, LLM proxy, Kai) are network-isolated within the namespace.
There is no existing API key mechanism for user-facing authentication.
Goals
tackle-admin,tackle-architect,tackle-migrator,tackle-project-managerroles and theirresource:methodscope mappings).Authorization: Bearer <key>by:Request.Permit()dual-provider flow)OPENAI_API_KEY=<konveyor-key>without modification.Non-Goals
Proposal
Key Lifecycle
Authentication Integration
The Hub already tries providers in sequence (
BuiltinthenKeycloak). The API key mechanism could be integrated as:Builtin, thenAPIKey, thenKeycloak), orBuiltinproviderThe provider would look up the key hash in the Hub database, resolve the associated user and their scopes, and return an
auth.Resultwith the sameAuthenticated/Authorized/User/Scopesstructure that Keycloak tokens produce.LLM Proxy Authentication
The LLM proxy currently validates JWTs independently against Keycloak's JWKS endpoint. This means it has its own parallel auth implementation that knows nothing about Hub-issued API keys. Rather than layering workarounds (multi-issuer JWKS, token exchange, etc.), this should be addressed architecturally:
Hub as the canonical auth/RBAC authority: All Konveyor services (LLM proxy, Kai/solution server, and any future services) should delegate authentication and authorization to a single source, either Hub itself or a dedicated auth service that Hub also uses. This centralizes API key validation, RBAC enforcement, and token lifecycle management in one place rather than having each service independently validate credentials against Keycloak.
This is a broader architectural change that extends beyond API keys. It would also simplify adding new services, ensure consistent RBAC enforcement, and eliminate the current pattern of each service needing its own Keycloak JWKS integration.
The exact form this takes (Hub exposes an auth validation endpoint that services call, a sidecar/middleware pattern, or a standalone auth service) is an open design question that needs further discussion.
Storage & Security
internal/secretfor Identity resources).Scoping
kai:get,kai:post).Management Interface
Related Issues
Open Questions