Skip to content
cccskills
FreePublished on GitHub

oauth-providers

Debug OAuth sign-in failures and add new OAuth providers to Keating (web + CLI). Use when a provider's "Sign in with …" flow fails, when adding a new OAuth provider, or when changing redirect URIs, token exchange, or refresh behavior.

The English summary is being prepared. Showing the original description.

Diogenesoftoronto/keating36 stars(GitHub 36 + cccskills 0)

Run score Not tested

See how to install

Files included (1)

  • SKILL.md6.6 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

OAuth providers in Keating

How OAuth sign-in works in this repo, the provider-specific quirks that have already caused bugs, and the checklist for adding a new provider.

Architecture

The web app uses an authorization-code + PKCE flow, brokered through the Nitro server so tokens are exchanged server-side:

PieceFileRole
Provider registryweb/src/keating/oauth.ts (OAUTH_PROVIDERS)Client IDs, authorize/token URLs, scopes, redirect URIs, extra authorize params
Redirect resolutionweb/src/keating/oauth.ts (resolveOAuthRedirectUri)Prod (keating.help) → https://keating.help/oauth/callback; everywhere else → the provider's CLI loopback URI + manual paste
Popup + pending stateweb/src/keating/oauth.ts (initiateOAuth)Saves {verifier, state, redirectUri} to localStorage under keating_oauth_pending, opens the authorize popup
Callback pageweb/src/pages/OAuthCallback.tsx (route /oauth/callback)Runs completeOAuthFromInput(location.href), posts keating-oauth-result message to the opener
Manual paste inputweb/src/components/settings/CloudProviderKeysSection.tsxShown while sign-in is pending; accepts a pasted callback URL, code#state, query string, or bare code
Token exchangeweb/server/api/oauth/token.tsPOSTs to the provider's token URL with the stored verifier
Token refreshweb/server/api/oauth/refresh.tsAuto-refresh 60s before expiry; 401/403 deletes stored credentials
Server client configweb/server/api/oauth/config.tsClient IDs/secrets, env-overridable (OAUTH_<PROVIDER>_CLIENT_ID / _SECRET)
Consumptionweb/src/lib/provider-models.ts (getProviderApiKey)OAuth token (or exchanged API key) wins over stored API keys
Reference implementationweb/node_modules/@earendil-works/pi-ai/dist/utils/oauth/*.jsThe CLI's working flows — check here first when a web flow misbehaves

Credentials are stored per provider as JSON under the oauth:<id> key in getAppStorage().providerKeys. Provider-name aliasing (openai → openai-codex, google → google-gemini-cli) lives in providerToOAuthId.

After editing web/src/keating/oauth.ts, regenerate the sandbox snapshot: bun scripts/generate-nodepod-boot-files.ts.

Provider quirks (hard-won; do not regress)

Anthropic (client 9d1c250a-e61b-44d9-88ed-5944d1962f5e, Codex Pro/Max):

  • The token endpoint https://platform.Codex.com/v1/oauth/token only accepts JSON bodies (Content-Type: application/json), for both code exchange and refresh. Form-urlencoded fails. This is special-cased in token.ts and refresh.ts.
  • Uses the provider-hosted code-display callback (https://platform.Codex.com/oauth/code/callback) in all environments; the user copies a code#state string. code=true must be in the authorize params or the code is never displayed.
  • state must equal the PKCE verifier (not a random value), and must be sent in the token exchange body.
  • Resulting sk-ant-oat-* access tokens are handled downstream by pi-ai (Bearer + anthropic-beta: oauth-2025-04-20 headers) — pass them through as the "apiKey"; do not put them in x-api-key yourself.

OpenAI Codex (client app_EMoamEEZ73f0CkXaXp7hrann, ChatGPT Plus/Pro):

  • Only http://localhost:1455/auth/callback is registered; any web-origin redirect is rejected at the authorize step (unless keating.help is registered on the client used — see redirect resolution above).
  • Form-urlencoded token exchange is correct here.
  • After exchange, the id_token is swapped for a real OpenAI API key via a token-exchange grant (web/server/api/oauth/openai-codex.ts, requested_token: openai-api-key).
  • Authorize needs id_token_add_organizations=true, codex_cli_simplified_flow=true, originator.

Google Gemini CLI (client 681255809395-oo8f…, installed app):

  • Installed-app clients accept any localhost port as redirect but no https origins, and the token exchange requires the client secret — the Gemini CLI's secret is public by design (embedded in its open-source repo; Google docs say installed-app secrets are not confidential) and is the fallback in web/server/api/oauth/config.ts.
  • Authorize needs access_type=offline&prompt=consent or no refresh token is returned.

Debugging a failing sign-in

  1. Reproduce and note which step fails:
    • Error on the provider's authorize page → redirect URI not registered for that client, or missing required authorize params.
    • "Token exchange failed: 502 …" from the app → server-side exchange rejected; check the Nitro log line [oauth/token] <provider> token exchange failed: <status> <body> for the upstream error.
    • Signed in but requests 401 → token consumed incorrectly (see quirks), or refresh failing ([oauth/refresh] log).
  2. Diff the failing flow against the CLI's pi-ai implementation (node_modules/@earendil-works/pi-ai/dist/utils/oauth/) — encoding (JSON vs form), authorize params, state semantics, redirect URI. Every web bug so far has been a divergence from those reference flows.
  3. Fix in the smallest layer (registry vs server handler), then run cd web && bun test src/test/oauth.test.ts && bunx tsc --noEmit.

Adding a new provider

  1. Add the entry to OAUTH_PROVIDERS in web/src/keating/oauth.ts (extend OAuthProviderId). Set redirectUri if the client only accepts a fixed loopback URI; leave it unset to use the web callback.
  2. Add server client config in web/server/api/oauth/config.ts (extend OAuthServerProviderId), with env overrides. Note the token body encoding the provider expects — special-case in token.ts/refresh.ts if not form-urlencoded.
  3. Map the app-facing provider name in providerToOAuthId and oauthProviderToProviderNames (CloudProviderKeysSection), and add a label to OAUTH_PROVIDER_LABELS.
  4. Wire consumption: confirm getProviderApiKey returns something the model client can use; if the provider needs a secondary exchange (like Codex → API key), do it server-side after the token response.
  5. Tests in web/src/test/oauth.test.ts: provider wiring, redirect URI resolution (prod + dev), and any exchange encoding special case.
  6. Regenerate nodepod boot files; run cd web && bun test && bunx tsc --noEmit.

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

Use when the user wants to learn, be taught, be quizzed, or understand an idea across any domain — science, math, philosophy, code, law, politics, psychology, medicine, arts, or history — with active scaffolding.

The English summary is being prepared. Showing the original description.

Diogenesoftoronto/keating36Updated Oct 20, 2026

ax

Free

This skill helps with using the @ax-llm/ax TypeScript library for building LLM applications. Use when the user asks about ax(), ai(), f(), s(), agent(), flow(), AxGen, AxAgent, AxFlow, signatures, streaming, or mentions @ax-llm/ax.

The English summary is being prepared. Showing the original description.

Diogenesoftoronto/keating36Updated Oct 20, 2026

This skill helps an LLM generate correct AxAgent code using @ax-llm/ax. Use when the user asks about agent(), child agents, namespaced functions, discovery mode, shared fields, llmQuery(...), RLM code execution, recursionOptions, or agent runtime behavior. For tuning and eval with agent.optimize(...), use ax-agent-optimize.

The English summary is being prepared. Showing the original description.

Diogenesoftoronto/keating36Updated Oct 20, 2026

This skill helps an LLM generate correct AxAgent tuning and evaluation code using @ax-llm/ax. Use when the user asks about agent.optimize(...), judgeOptions, eval datasets, optimization targets, saved optimizedProgram artifacts, or recursive optimization guidance.

The English summary is being prepared. Showing the original description.

Diogenesoftoronto/keating36Updated Oct 20, 2026

ax-ai

Free

This skill helps an LLM generate correct AI provider setup and configuration code using @ax-llm/ax. Use when the user asks about ai(), providers, models, presets, embeddings, extended thinking, context caching, or mentions OpenAI/Anthropic/Google/Azure/Groq/DeepSeek/Mistral/Cohere/Together/Ollama/HuggingFace/Reka/OpenRouter with @ax-llm/ax.

The English summary is being prepared. Showing the original description.

Diogenesoftoronto/keating36Updated Oct 20, 2026

This skill helps an LLM generate correct AxFlow workflow code using @ax-llm/ax. Use when the user asks about flow(), AxFlow, workflow orchestration, parallel execution, DAG workflows, conditional routing, map/reduce patterns, or multi-node AI pipelines.

The English summary is being prepared. Showing the original description.

Diogenesoftoronto/keating36Updated Oct 20, 2026

See all skills by Diogenesoftoronto

Report a problem with this skill