Skip to content

Enhancement: Long-lived API key mechanism for Konveyor Hub #266

Description

@fabianvf

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:

  • Agent subprocesses (Goose, OpenCode): The editor-extensions project spawns these with LLM proxy credentials in environment variables at launch time. Once the token expires, every LLM request fails with 403. See Agent subprocess credentials expire with no way to refresh them editor-extensions#1334.
  • 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:

  1. 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.
  2. 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.

  3. 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.

  4. 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

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).

Related Issues

Open Questions

  • Should API keys be scoped to specific services (LLM proxy only, Hub API only) or always grant the user's full role?
  • What form should centralized auth take, Hub as the authority or a dedicated auth service?
  • Should there be a maximum TTL policy that admins can configure?
  • How should API key usage be audited/logged?

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-kindIndicates an issue or PR lacks a `kind/foo` label and requires one.needs-priorityIndicates an issue or PR lacks a `priority/foo` label and requires one.needs-triageIndicates an issue or PR lacks a `triage/foo` label and requires one.stale

    Type

    No type

    Projects

    • Status
      🔖 Ready

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions