Skip to content

Per-model API-key scoping broken when one user has keys for multiple models (colliding client IDs) #122

Description

@dcmcand

Found while testing #117 live.

Once a user mints API keys for more than one model, per-model scoping breaks: a key minted for model A is accepted for model B, and the user's other keys stop authenticating entirely.

Root cause: key-manager/internal/secrets/manager.go computes the key sequence by counting the user's keys in that one model's Secret, so the first key a user mints for any model is always user-<name>-1. The operator pools every model's api-keys Secret into each model's SecurityPolicy credentialRefs (the pooled-authentication design in #117) and forwards the matched data key as x-llm-client-id for per-model authorization. Identical client IDs across models collide in that pooled set:

  • only one Secret's value survives per duplicated client ID, so the user's other keys return 401
  • the surviving client ID is in every model's allow-list, so that key is authorized cross-model (200)

Live evidence: user llm-test with keys for two OpenRouter models and one served model. All three keys had client ID user-llm-test-1. Only one key authenticated, and it returned 200 on a model it was not minted for.

Impact: defeats the per-model scoping #117 implements (its stated guarantee is "a key minted for model A returns 200 for A and 403 for every other model"), and makes legitimately-minted keys unusable. Surfaces whenever one user has keys for multiple models; single-model-per-user tests do not hit it.

Fix: scope the client ID by model (user-<name>-<model>-<n>) so it is globally unique. Done on the #117 branch (commit d9f5a15) with a regression test that mints for two models as one user and asserts distinct client IDs.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    Priority

    None yet

    Start date

    None yet

    Target date

    None yet

    Size

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions