Back to Skills

extension-openai

MANDATORY recipe for every Caffeine build that calls OpenAI (ChatGPT, GPT-4o, an LLM, a chatbot, embeddings). The ONLY supported path is the `openai-client` mops package with a canister-side API-key bearer. Hand-rolling `ic.http_request` to `api.openai.com/v1/...` is a FORBIDDEN anti-pattern — it leaks the bearer across replicated outcalls (security + 13× billing impact), bypasses the typed request/response bindings, and forces hand-rolled JSON on a language with poor JSON support. Load this ski

Updated 6/26/2026

Security Assessment

Safe(100/100)
Security Score100/100

About extension-openai

This extension is the mandatory recipe for any Caffeine build that calls OpenAI, covering ChatGPT, GPT models, general LLM use, chatbots, and embeddings. The only supported path is the openai-client mops package (curated Motoko bindings for the OpenAI REST API generated from OpenAPI spec 2.3.0, with a curated subset spanning Chat, Completions, Embeddings, Images, Audio, Moderations, Models, and Files) using a canister-side API-key bearer. Hand-rolling ic.http_request calls to api.openai.com/v1/... is a forbidden anti-pattern because it leaks the bearer across replicated outcalls (a security and roughly 13x billing impact), bypasses the typed request/response bindings, and forces hand-rolled JSON on a language with weak JSON support.

Unlike X, OpenAI uses a single static bearer per account, an sk-... key, with no OAuth, PKCE, callback URL, or refresh rotation. The skill defines three storage variants the spec picks from: per-user keys (the default) where each signed-in user pastes their own sk-... key and funds their own usage, gated on a non-anonymous caller; an admin key set once by an admin and used for every call, gated on the extension-authorization #admin role, for operator-funded SaaS or freemium tiers; and a fully anonymous variant with no auth gate where any visitor may set or replace the single key, used only when the spec is explicit that there is no login. extension-authorization is a prerequisite for the per-user and admin-key variants (it ships the Internet Identity login flow and backend caller/role infrastructure), while the fully anonymous variant does not require it.

All variants share strict security invariants. The Config value must pin is_replicated = ?false, the package must be at least openai-client 0.2.5 (added with mops add [email protected], which requires Mops at least 2.13 for atomic lockfile updates), and the key must never be returned by any query or shared function, never logged, never sent to the frontend, and never placed in a stable variable that a weaker-gated endpoint could read. The frontend only ever learns whether a key is configured, as a Bool, never the key value. The bearer is long-lived with no expiry, has full unscoped account access, and should be treated as a billing credential rather than a session token. Use this skill for any feature that summarizes, classifies, answers, builds a chatbot, or generates embeddings via OpenAI.

FAQ

Why shouldn't I call api.openai.com directly from the canister?

Raw ic.http_request calls to api.openai.com leak the bearer across replicated outcalls (a security and ~13x billing impact), bypass the typed bindings, and force hand-rolled JSON. The openai-client mops package with a canister-side API-key bearer is the only supported path.

Which key-storage variant is the default?

Per-user keys are the default: each signed-in user pastes their own sk-... key and funds their own usage. Switch to the admin-key variant when the operator explicitly pays for all users, or the fully anonymous variant only when the spec says there is no login at all.

Does OpenAI integration use OAuth like the X extension?

No. OpenAI uses a single static sk-... bearer per account with no OAuth, PKCE, callback URL, or refresh-token rotation; the key is stored as a canister-side secret.

Is the API key ever exposed to the frontend?

No. The bearer never leaves the canister and is never returned by a query or shared function, logged, or sent to the frontend; the frontend only learns whether a key is configured, as a Bool.

What version and configuration are required?

Use openai-client version 0.2.5 or later (added via mops add [email protected], which needs Mops 2.13+), and the Config value must pin is_replicated = ?false.

Install extension-openai

Download and extract the skill files to your .claude/skills/ directory.

Quick Setup:

  1. Copy the skill folder to .claude/skills/
  2. Claude will automatically detect and use the skill