docs: RFC 8707 resource field + extra_token_params for openai-compatible OAuth (all three flows, merge/precedence notes)

Dark-Alex-17 committed 2026-09-14 18:31:48 -06:00
1 parent b87cafd75d
commit 338da31a43
1 file changed
+19
+19
@@ -288,6 +288,10 @@ copy/paste), but requires that the provider's OAuth app allows a loopback redire
**Optional fields:** **Optional fields:**
- `scopes: [scope1, scope2]`: space-joined into the `scope=` query param. - `scopes: [scope1, scope2]`: space-joined into the `scope=` query param.
- `extra_authorize_params: { key: value }`: extra query params on the authorize URL (e.g. xAI needs `plan: generic`). - `extra_authorize_params: { key: value }`: extra query params on the authorize URL (e.g. xAI needs `plan: generic`).
- `extra_token_params: { key: value }`: extra form params on every token request (code exchange and refresh); the
token-side mirror of `extra_authorize_params`.
- `resource: <uri>`: RFC 8707 resource indicator. Sent as `resource=` on the authorize URL and on every token
request (code exchange and refresh). Use this when your provider scopes tokens to a specific API/resource server.
- `echo_pkce_in_token_exchange: true`: some providers (like xAI) require re-sending `code_challenge` on token exchange. - `echo_pkce_in_token_exchange: true`: some providers (like xAI) require re-sending `code_challenge` on token exchange.
- `include_state_in_token_exchange: false`: some providers reject `state` on the token endpoint (default `true`). - `include_state_in_token_exchange: false`: some providers reject `state` on the token endpoint (default `true`).
- `token_request_format: form_url_encoded`: some providers require form-encoded token bodies (default is - `token_request_format: form_url_encoded`: some providers require form-encoded token bodies (default is
@@ -359,6 +363,10 @@ are supported.
- `scopes: [scope1, scope2]` - `scopes: [scope1, scope2]`
- `use_pkce_in_device_flow: true`: some providers (like MiniMax) require PKCE with device flow. Coyote generates a - `use_pkce_in_device_flow: true`: some providers (like MiniMax) require PKCE with device flow. Coyote generates a
fresh `code_verifier` + `code_challenge` (S256) on each authentication. fresh `code_verifier` + `code_challenge` (S256) on each authentication.
- `extra_token_params: { key: value }`: extra form params on every token request (device polling and refresh).
- `resource: <uri>`: RFC 8707 resource indicator. Sent as `resource=` on the device-authorization request and on
every token request (device polling and refresh). Use this when your provider scopes tokens to a specific
API/resource server.
- `token_request_format: form_url_encoded`: usually needed for device flow (default for openai-compatible). - `token_request_format: form_url_encoded`: usually needed for device flow (default for openai-compatible).
- `extra_token_headers: { key: value }`: custom headers applied to both device and token endpoints. - `extra_token_headers: { key: value }`: custom headers applied to both device and token endpoints.
- `client_secret`: rare but supported. - `client_secret`: rare but supported.
@@ -375,6 +383,7 @@ clients:
device_authorization_url: https://auth.example.com/oauth/device_authorization device_authorization_url: https://auth.example.com/oauth/device_authorization
token_url: https://auth.example.com/oauth/token token_url: https://auth.example.com/oauth/token
flow: device_code flow: device_code
resource: https://api.example.com/
scopes: [openid, profile] scopes: [openid, profile]
``` ```
@@ -395,6 +404,8 @@ For headless machine-to-machine authentication. No user, no browser. Coyote POST
**Optional fields:** **Optional fields:**
- `scopes: [scope1, scope2]` - `scopes: [scope1, scope2]`
- `token_request_format` - `token_request_format`
- `extra_token_params: { key: value }`: extra form params on the token request (and each silent re-exchange).
- `resource: <uri>`: RFC 8707 resource indicator, sent as `resource=` on the token request.
- `extra_token_headers: { key: value }` - `extra_token_headers: { key: value }`
**Example:** **Example:**
@@ -439,6 +450,14 @@ which field is missing.
You can override individual fields. For example, if the bundled default has the wrong token URL for your corporate You can override individual fields. For example, if the bundled default has the wrong token URL for your corporate
gateway, just set `oauth.token_url` inline and the rest of the bundled defaults still apply. gateway, just set `oauth.token_url` inline and the rest of the bundled defaults still apply.
Two special cases:
- **Map fields merge per-key** rather than being replaced wholesale: `extra_authorize_params`, `extra_token_params`,
and `extra_token_headers` from `config.yaml` are merged into the bundled defaults, with your keys winning on conflict.
- **A `resource` entry inside `extra_authorize_params` / `extra_token_params` wins over the first-class `resource`
field** on its respective request surface. This keeps configs that predate the `resource` field (which passed it via
the extra-params maps) working without sending duplicate or conflicting `resource=` values.
### Known Limitation: Token Namespacing ### Known Limitation: Token Namespacing
OAuth tokens are stored on disk at `~/.cache/coyote/oauth/{client_name}_oauth_tokens.json`, keyed by the client's `name` OAuth tokens are stored on disk at `~/.cache/coyote/oauth/{client_name}_oauth_tokens.json`, keyed by the client's `name`