From d215e436fabf2475c126374d437898670b262208 Mon Sep 17 00:00:00 2001 From: Stephane Segning Lambou Date: Fri, 29 May 2026 11:38:33 +0200 Subject: [PATCH] docs: add a combined oauth2 + models-info example Show one provider authenticated by @vymalo/opencode-oauth2 and enriched by @vymalo/opencode-models-info, with the key gotcha called out: list the oauth2 plugin first so its config hook stamps the bearer onto the provider headers before models-info runs its fetch. Added to the top-level README companion section and the package README's Auth composition section. Uses the absolute modelsInfoUrl form for clarity; no models block / Authorization header needed. Co-Authored-By: Claude Opus 4.7 (1M context) --- README.md | 26 +++++++++++++++++++++++++ packages/opencode-models-info/README.md | 26 +++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/README.md b/README.md index 880ec77..046380f 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,32 @@ The expected JSON is commonly called the **OpenRouter shape** (it's what OpenRou It doesn't depend on the oauth2 plugin — it runs as a `config` hook *after* other plugins, composing with oauth2, static API keys, or no auth. When paired with `@vymalo/opencode-oauth2` ≥ 0.4.0, an OAuth2-protected metadata endpoint works with zero extra config: the oauth2 plugin stamps the cached bearer onto the provider's headers at config time and the metadata fetch inherits it. +### Both plugins together + +One provider, authenticated by oauth2 and enriched by models-info. List `@vymalo/opencode-oauth2` **first** so its `config` hook runs before models-info and the bearer is already in place when the metadata fetch happens: + +```jsonc +{ + "plugin": ["@vymalo/opencode-oauth2", "@vymalo/opencode-models-info"], + "provider": { + "my-provider": { + "npm": "@ai-sdk/openai-compatible", + "options": { + "baseURL": "https://api.example.com/v1", + "oauth2": { + "issuer": "https://auth.example.com", + "clientId": "opencode-client", + "scopes": ["openid", "profile", "offline_access"] + }, + "meta": { "modelsInfoUrl": "https://api.example.com/v1/models" } + } + } + } +} +``` + +What happens on boot: oauth2 authenticates, discovers models from `/v1/models`, and stamps the access token onto the provider's headers; models-info then fetches `modelsInfoUrl` with that token and merges the richer metadata onto the discovered models. No `models` block needed — oauth2 populates it. No `Authorization` header to manage — it's automatic. + Full reference: [`packages/opencode-models-info/README.md`](packages/opencode-models-info/README.md). Behavior, caching, and composition details: [`docs/models-info.md`](docs/models-info.md). ## Federated identity (CI / Kubernetes) diff --git a/packages/opencode-models-info/README.md b/packages/opencode-models-info/README.md index 835d5c2..9858318 100644 --- a/packages/opencode-models-info/README.md +++ b/packages/opencode-models-info/README.md @@ -89,6 +89,32 @@ The plugin sends the union of `options.headers` and `meta.modelsInfoHeaders` (me If you need a different token for the metadata endpoint than for inference (e.g. a service-account bearer), set it explicitly under `meta.modelsInfoHeaders.Authorization` — it'll override whatever the provider has set. +#### Example: with `@vymalo/opencode-oauth2` + +List the oauth2 plugin **first** so its `config` hook runs before this one — that's what puts the bearer on `options.headers` in time for the metadata fetch: + +```jsonc +{ + "plugin": ["@vymalo/opencode-oauth2", "@vymalo/opencode-models-info"], + "provider": { + "my-provider": { + "npm": "@ai-sdk/openai-compatible", + "options": { + "baseURL": "https://api.example.com/v1", + "oauth2": { + "issuer": "https://auth.example.com", + "clientId": "opencode-client", + "scopes": ["openid", "profile", "offline_access"] + }, + "meta": { "modelsInfoUrl": "https://api.example.com/v1/models" } + } + } + } +} +``` + +oauth2 authenticates the provider and discovers its models; this plugin then fetches `modelsInfoUrl` using the token oauth2 stamped onto the provider headers, and enriches those discovered models. No `models` block and no `Authorization` header to manage — both are handled for you. + ### Expected response shape (OpenRouter) ```json