# How to Configure Authentication Mechanisms for Your OpenAI Plugin: A Complete Guide

> Learn to configure authentication for your OpenAI plugin. Explore OAuth 2.0 flows, register credentials, and set up your plugin runtime for secure access. A complete guide for developers.

- Repository: [OpenAI/plugins](https://github.com/openai/plugins)
- Tags: how-to-guide
- Published: 2026-06-29

---

**Configure authentication for your OpenAI plugin by selecting the appropriate OAuth 2.0 flow (PKCE, Server-to-Server, or JWT), registering credentials in the service's developer portal, and wiring environment variables into your plugin runtime.**

The `openai/plugins` repository provides standardized patterns for connecting to external services like Zoom, requiring robust authentication handling. Whether you are building user-driven apps or backend integrations, understanding how to configure these mechanisms ensures secure API access. This guide covers the three primary authentication flows implemented in the repository, using Zoom-specific examples that apply universally across supported services.

## Understanding Authentication Patterns in OpenAI Plugins

The repository supports three distinct authentication strategies, each designed for specific integration architectures.

### OAuth 2.0 with PKCE (User-Driven)

**OAuth 2.0 with PKCE** (Proof Key for Code Exchange) is the standard for user-permission flows in client-side applications. This pattern appears in [`plugins/zoom/skills/zoom-apps-sdk/references/oauth.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/zoom-apps-sdk/references/oauth.md) and requires a `client_id`, `client_secret`, and redirect URI registered in the service's marketplace. Use this flow when your plugin needs to act on behalf of an end user, such as accessing Zoom meeting data or user profiles.

### Server-to-Server OAuth (Backend-Only)

**Server-to-Server OAuth** enables machine-to-machine authentication without user interaction. As documented in [`plugins/zoom/skills/websockets/references/full-guide.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/websockets/references/full-guide.md), this flow uses client credentials that never involve a browser redirect. Deploy this pattern for background sync operations, administrative tasks, or when your plugin functions as a trusted server component.

### JWT for Legacy Video SDK

**JWT authentication** provides stateless, signed tokens for the Video SDK. According to [`plugins/zoom/skills/video-sdk/references/authorization.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/video-sdk/references/authorization.md), this legacy method requires generating a token signed with your API key and secret on every request. Use JWT only when integrating with the Zoom Video SDK specifically, as newer implementations favor OAuth 2.0.

## Step-by-Step Configuration Guide

Follow these steps to implement authentication in your plugin, regardless of the specific service.

### Register Credentials in the Developer Portal

First, create your application in the service's developer console. For Zoom Apps, navigate to **Marketplace → App Credentials** and enable the required OAuth scopes. Add your **Redirect URI** (e.g., `https://your-domain.com/auth`) to the OAuth Allow List, ensuring it matches the value you will configure in your environment. The complete scope mapping is available in [`plugins/zoom/skills/zoom-apps-sdk/references/full-guide.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/zoom-apps-sdk/references/full-guide.md).

### Configure Environment Variables

Store sensitive credentials in environment variables, never in source control. The canonical variable list is defined in [`plugins/zoom/skills/zoom-apps-sdk/references/environment-variables.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/zoom-apps-sdk/references/environment-variables.md):

```bash
ZOOM_APP_CLIENT_ID=your_client_id_here
ZOOM_APP_CLIENT_SECRET=your_client_secret_here
ZOOM_APP_REDIRECT_URI=https://your-domain.com/auth

```

Load these via your deployment environment's secret manager or a local `.env` file during development.

### Implement the Token Exchange Endpoint

Create a backend endpoint to handle the authorization code exchange. This implementation from [`plugins/zoom/skills/zoom-apps-sdk/examples/in-client-oauth.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/zoom-apps-sdk/examples/in-client-oauth.md) demonstrates the PKCE flow:

```javascript
// File: server/auth.js
import express from 'express';
import axios from 'axios';
const router = express.Router();

router.post('/api/auth/token', async (req, res) => {
  const { code, codeVerifier } = req.body;
  
  const tokenResponse = await axios.post(
    'https://zoom.us/oauth/token',
    null,
    {
      params: {
        grant_type: 'authorization_code',
        code,
        redirect_uri: process.env.ZOOM_APP_REDIRECT_URI,
        code_verifier: codeVerifier,
      },
      auth: {
        username: process.env.ZOOM_APP_CLIENT_ID,
        password: process.env.ZOOM_APP_CLIENT_SECRET,
      },
    }
  );
  
  res.json(tokenResponse.data);
});

export default router;

```

Store the returned `access_token` and `refresh_token` securely, associating them with the user's session.

### Trigger Authentication from the Frontend

Initiate the flow from your client application using the Zoom SDK. This pattern from [`plugins/zoom/skills/zoom-apps-sdk/examples/in-client-oauth.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/zoom-apps-sdk/examples/in-client-oauth.md) shows the frontend implementation:

```javascript
import { zoomSdk } from '@zoom/app-sdk';

async function startAuth() {
  // Generate PKCE challenge from backend
  const { codeChallenge, state } = await fetch('/api/auth/challenge')
    .then(r => r.json());

  // Launch OAuth popup
  await zoomSdk.authorize({ codeChallenge, state });

  // Listen for completion
  zoomSdk.on('onAuthorized', async () => {
    const status = await fetch('/api/auth/status').then(r => r.json());
    console.log('Authorization status:', status.authorized);
  });
}

```

The `zoomSdk.authorize()` method handles the browser redirect and returns control to your app upon completion.

### Handle Token Refresh and Expiry

OAuth tokens expire and require refreshing. When you detect a 401 response or approaching expiry, exchange the stored `refresh_token` for a new `access_token` using the same token endpoint with `grant_type=refresh_token`. The refresh logic is demonstrated in [`plugins/zoom/skills/zoom-apps-sdk/examples/quick-start.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/zoom-apps-sdk/examples/quick-start.md).

## Verifying Scopes and Capabilities

SDK capabilities must align with your registered OAuth scopes. For example, calling `zoomSdk.authorize()` requires the `in_meeting_app` scope, while `getUserContext` needs additional user data permissions. Mismatches cause silent failures documented in [`plugins/zoom/skills/zoom-apps-sdk/troubleshooting/common-issues.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/zoom-apps-sdk/troubleshooting/common-issues.md). Update scopes via the Marketplace UI and redeploy your plugin after any changes.

## Testing Your Authentication Flow

Validate your configuration before production deployment:

1. Tunnel your local development server using ngrok and update the Redirect URI in the Marketplace.
2. Launch the app within a Zoom meeting and trigger the authorization flow.
3. Verify that `GET /api/auth/status` returns `{ authorized: true }`.
4. Test API calls using the stored token: `curl -H "Authorization: Bearer <token>" https://api.zoom.us/v2/users/me`.

If authentication fails, check the troubleshooting guide at [`plugins/zoom/skills/zoom-apps-sdk/troubleshooting/common-issues.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/zoom-apps-sdk/troubleshooting/common-issues.md) for common pitfalls like redirect URI mismatches or missing scopes.

## Summary

- **Choose the correct flow**: Use OAuth 2.0 PKCE for user actions, Server-to-Server OAuth for backend operations, and JWT only for legacy Video SDK integrations.
- **Secure your credentials**: Store `CLIENT_ID`, `CLIENT_SECRET`, and `REDIRECT_URI` in environment variables, never in source code.
- **Implement token exchange**: Create backend endpoints to handle authorization codes and refresh tokens, as shown in [`in-client-oauth.md`](https://github.com/openai/plugins/blob/main/in-client-oauth.md).
- **Align scopes and capabilities**: Ensure your Marketplace app scopes match the SDK methods you call to prevent silent authorization failures.
- **Test thoroughly**: Use ngrok tunnels and direct API calls to verify tokens work before deploying to production.

## Frequently Asked Questions

### What is the difference between PKCE and Server-to-Server OAuth in OpenAI plugins?

PKCE (Proof Key for Code Exchange) is designed for user-facing applications where a browser or client initiates the authorization flow and receives a user-specific token. Server-to-Server OAuth uses client credentials to obtain tokens without user interaction, suitable for backend services running administrative tasks. The repository implements PKCE in [`plugins/zoom/skills/zoom-apps-sdk/references/oauth.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/zoom-apps-sdk/references/oauth.md) and Server-to-Server flows in [`plugins/zoom/skills/rest-api/concepts/authentication-flows.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/rest-api/concepts/authentication-flows.md).

### Where should I store my plugin's client credentials?

Store credentials exclusively in environment variables or your deployment platform's secret management system. The file [`plugins/zoom/skills/zoom-apps-sdk/references/environment-variables.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/zoom-apps-sdk/references/environment-variables.md) documents the required variables (`ZOOM_APP_CLIENT_ID`, `ZOOM_APP_CLIENT_SECRET`, `ZOOM_APP_REDIRECT_URI`). Never commit these values to version control or include them in frontend bundles.

### How do I handle token expiration in a production plugin?

Implement automatic token refresh using the `refresh_token` returned during the initial authorization. When your backend detects an expired `access_token` (HTTP 401 response), call the token endpoint with `grant_type=refresh_token` to obtain a new access token without requiring user re-authentication. Store refresh tokens securely in your database associated with the user session.

### Why does my plugin fail to authorize even with correct credentials?

Authorization failures typically stem from scope mismatches between your Marketplace app registration and your SDK usage. If your code calls `zoomSdk.getUserContext()` but the app lacks the `user:read` scope, the request fails silently. Verify that all capabilities used in your code are explicitly enabled in the Marketplace under **App Credentials → Scopes**, and consult [`plugins/zoom/skills/zoom-apps-sdk/troubleshooting/common-issues.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/zoom-apps-sdk/troubleshooting/common-issues.md) for detailed debugging steps.