Authentication Requirements for Plugins in the OpenAI Repository: Manifest and Skill Implementation

Plugins in the openai/plugins repository must declare their authentication scheme in the manifest’s authentication field and implement the corresponding flow in skill files to securely access third-party APIs.

The openai/plugins repository provides a framework for extending OpenAI’s platform through external service integrations. Because these plugins invoke third-party APIs, satisfying the authentication requirements for plugins is mandatory before any skill code executes. Each plugin must define its auth model at both the manifest level and the skill implementation level according to the target service’s specifications.

Manifest-Level Authentication Declaration

Every plugin’s root directory contains a *.codex-plugin/plugin.json manifest file that defines the plugin’s structure and requirements. The manifest includes an authentication field that declares which auth scheme the plugin expects, such as api_key, oauth2, or jwt.

This declaration allows the OpenAI runtime to enforce the correct authentication flow before executing any skill code. If the request lacks the credentials specified in the manifest, the platform rejects the call with a 401 error. The generic manifest layout is described in the repository’s README.md.

Skill-Level Implementation

Concrete authentication logic resides in the skill files under plugins/<name>/skills/…. Each skill includes a "References" section pointing to a markdown file describing the exact flow used by that plugin.

According to the openai/plugins source code, the Zoom plugins demonstrate this pattern clearly:

Supported Authentication Mechanisms

The repository supports multiple authentication patterns to accommodate different third-party service requirements.

API-Key and Bearer Tokens

API-Key authentication is used for simple service-to-service calls where the provider issues a static token. The plugin adds Authorization: Bearer <token> to each request header.

This pattern appears throughout the repository, with the Zoom OAuth reference demonstrating the Authorization header convention. This method requires no token refresh logic since the key remains static.

OAuth 2.0 Authorization Code with PKCE

OAuth 2.0 Authorization Code with PKCE handles user-delegated access where explicit consent is required. The plugin generates a PKCE challenge, redirects the user to the provider’s authorization endpoint, exchanges the authorization code for an access token, and stores the token for subsequent calls.

In the Zoom Apps SDK implementation, skill code calls zoomSdk.authorize({ codeChallenge, state }) to initiate the flow. The detailed PKCE implementation is documented in plugins/zoom/skills/zoom-apps-sdk/references/oauth.md.

OAuth 2.0 Client Credentials

OAuth 2.0 Client Credentials (server-to-server) supports background services that act on behalf of the application rather than a user. This flow uses the client ID and secret to obtain a token without user interaction.

The token endpoint accepts grant_type=client_credentials and returns an access token for API calls. This pattern is described in plugins/zoom/skills/rest-api/concepts/authentication-flows.md and commonly used for Zoom Webhooks and internal bots.

JSON Web Tokens (JWT)

JWT authentication is used by the legacy Zoom Video SDK and high-performance APIs that require signed requests. The plugin creates a JWT using the SDK key and secret, setting claims such as iss (issuer) and exp (expiration).

The JWT generation steps are documented in plugins/zoom/skills/video-sdk/references/authorization.md. Each request includes the token in the Authorization: JWT <signed_token> header.

Authentication Lifecycle

The authentication process follows a strict lifecycle from validation to error handling.

  1. Manifest Validation – The OpenAI platform validates that the plugin’s manifest lists an accepted authentication type before executing any code.

  2. Token Acquisition – Skill code initiates the appropriate flow, such as zoomSdk.authorize() for in-client OAuth or server-side requests for client credentials.

  3. Token Storage and Refresh – Access tokens are cached (often in DynamoDB for Zoom implementations) and refreshed before expiry using the /oauth/token endpoint with grant_type=refresh_token.

  4. Header Injection – Every outbound HTTP request attaches the appropriate header, either Authorization: Bearer <access_token> or Authorization: JWT <signed_token>.

  5. Error Handling – When calls return 401 or 403 status codes, the skill triggers a re-authentication flow as outlined in plugins/zoom/skills/oauth/references/oauth-errors.md.

Implementation Examples

Below are minimal implementations demonstrating each authentication pattern.

Bearer Token Implementation

import fetch from 'node-fetch';

async function callExternalApi(endpoint, apiKey) {
  const res = await fetch(endpoint, {
    headers: { 'Authorization': `Bearer ${apiKey}` },
  });
  return res.json();
}

OAuth 2.0 PKCE Implementation

async function startPkceFlow() {
  const challenge = await fetch('/api/auth/challenge').then(r => r.json());
  await zoomSdk.authorize({ 
    codeChallenge: challenge.codeChallenge, 
    state: challenge.state 
  });
  // Listen for the onAuthorized callback to receive the access token
}

OAuth 2.0 Client Credentials Implementation

import axios from 'axios';

async function getServerToken(clientId, clientSecret) {
  const resp = await axios.post('https://zoom.us/oauth/token', null, {
    params: { grant_type: 'client_credentials' },
    auth: { username: clientId, password: clientSecret },
  });
  return resp.data.access_token;
}

JWT Implementation

import jwt from 'jsonwebtoken';

function makeJwt(sdkKey, sdkSecret) {
  const payload = { 
    iss: sdkKey, 
    exp: Math.floor(Date.now() / 1000) + 3600 
  };
  return jwt.sign(payload, sdkSecret);
}

Summary

  • Plugins must declare authentication requirements in *.codex-plugin/plugin.json using the authentication field to enable runtime validation.
  • Skill-level authentication logic is implemented in plugins/<name>/skills/ directories with detailed flows documented in reference markdown files.
  • Supported mechanisms include API-Key/Bearer tokens, OAuth 2.0 (PKCE and Client Credentials), and JWT, each suited to different integration patterns.
  • The authentication lifecycle includes manifest validation, token acquisition, storage with refresh logic, header injection, and error handling via re-authentication flows.

Frequently Asked Questions

Where are authentication requirements declared for a plugin?

Authentication requirements are declared in the plugin’s manifest file at *.codex-plugin/plugin.json. The authentication field specifies the required scheme (such as api_key, oauth2, or jwt), which allows the OpenAI runtime to validate credentials before executing skill code.

What is the difference between manifest-level and skill-level authentication?

Manifest-level authentication acts as a gateway check—the platform validates that required credentials exist before running any code. Skill-level authentication contains the actual implementation logic, such as calling zoomSdk.authorize() or generating JWT signatures, and resides in files under plugins/<name>/skills/.

How does token refresh work in the OpenAI plugins authentication lifecycle?

Tokens are cached in persistent storage (often DynamoDB for Zoom-based plugins) and refreshed before expiration using the provider’s token endpoint with grant_type=refresh_token. The refresh logic is typically implemented in plugins/<name>/skills/rest-api/references/authentication.md for OAuth-based plugins.

Which authentication mechanism should I use for server-to-server integrations?

For server-to-server integrations that do not require user consent, use OAuth 2.0 Client Credentials. This flow authenticates using only the client ID and secret without user interaction, as documented in plugins/zoom/skills/rest-api/concepts/authentication-flows.md.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →