Skip to content

models.list_for_user() requires a separate security= argument because the spec declares a duplicate bearer security scheme #581

Description

@rajarshidattapy

Summary

models.list_for_user() is the only method in the SDK (1 of 95 operations) that requires
an operation-level security= argument. The api_key passed to the OpenRouter client is
ignored for this one call, so users must supply the same credential twice, through a
differently-named type and a differently-named env var.

The cause is a duplicate security scheme in the OpenAPI document, not the generator.

Steps to reproduce

from openrouter import OpenRouter

client = OpenRouter(api_key="sk-or-v1-...")
client.models.list()           # works
client.models.list_for_user()  # TypeError

Actual behavior

TypeError: Models.list_for_user() missing 1 required keyword-only argument: 'security'

The signature (src/openrouter/models_.py:1067) makes security required and non-defaulted:

def list_for_user(
    self,
    *,
    security: Union[
        operations.ListModelsUserSecurity,
        operations.ListModelsUserSecurityTypedDict,
    ],
    ...

The only way to call it is to re-pass the key that the client already holds:

from openrouter import OpenRouter, operations

client = OpenRouter(api_key="sk-or-v1-...")
client.models.list_for_user(
    security=operations.ListModelsUserSecurity(bearer="sk-or-v1-...")  # same key, again
)

docs/sdks/models/README.mdx:210 compounds this by reading it from a second env var,
OPENROUTER_BEARER, while every other snippet in the docs uses OPENROUTER_API_KEY.

Expected behavior

client.models.list_for_user() authenticates with the client-level api_key, like every
other method on the SDK.

Root cause

.speakeasy/out.openapi.yaml defines two security schemes that are identical down to the
description:

securitySchemes:
  apiKey:
    description: 'API key as bearer token in Authorization header'
    scheme: 'bearer'
    type: 'http'
  bearer:
    description: 'API key as bearer token in Authorization header'
    scheme: 'bearer'
    type: 'http'

Global security is apiKey:

security:
  - apiKey: []

listModelsUser (GET /models/user) is the single operation that overrides it with the
other name:

      operationId: 'listModelsUser'
      ...
      security:
        - bearer: []

Counts across the whole document:

  • apiKey: [] appears 8 times
  • bearer: [] appears exactly once — on this operation.

Both in.openapi.yaml and out.openapi.yaml agree, so it originates upstream in the
monorepo spec rather than in an overlay.

Because the scheme name differs from the global one, hoistGlobalSecurity /
flattenGlobalSecurity can't apply, and the generator emits a required per-operation
security parameter.

Suggested fix

One line upstream — either point the operation at the existing global scheme:

      security:
        - apiKey: []

or drop the per-operation security block entirely so it inherits the global one, and
remove the now-unused bearer scheme from components.securitySchemes.

Environment

  • openrouter 1.1.23 (main @ cb401a8)
  • Python 3.11.9, httpx 0.28.1, pydantic 2.12.4
  • Windows 11

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions