# Connect to your own API

Secure backend access with OIDC federation is available on [all plans](/content/docs/plans/index.html).

## [Validate the tokens](/content/docs/oidc/api#validate-the-tokens/index.html)

To configure your own API to accept Vercel's OIDC tokens, you need to validate the tokens using Vercel's JSON Web Keys (JWTs), available at `https://oidc.vercel.com/[TEAM_SLUG]/.well-known/jwks` with the team issuer mode, and `https://oidc.vercel.com/.well-known/jwks` for the global issuer mode.

### [Use the `jose.jwtVerify` function](/content/docs/oidc/api#use-the-jose.jwtverify-function/index.html)

Install the following package:

```bash
pnpm i jose
```

```bash
yarn add jose
```

```bash
npm i jose
```

```bash
bun add jose
```

In the code example below, you use the `jose.jwtVerify` function to verify the token. The `issuer`, `audience`, and `subject` are validated against the token's claims.

```typescript
import http from 'node:http';
import * as jose from 'jose';

const ISSUER_URL = `https://oidc.vercel.com/[TEAM_SLUG]`;
// or use `https://oidc.vercel.com` if your issuer mode is set to Global.

const JWKS = jose.createRemoteJWKSet(new URL(ISSUER_URL, '/.well-known/jwks'));

const server = http.createServer(async (req, res) => {
  const token = req.headers['authorization']?.split('Bearer ')[1];

if (!token) {
    res.statusCode = 401;
    res.end('Unauthorized');
    return;
  }

try {
    const { payload } = await jose.jwtVerify(token, JWKS, {
      issuer: ISSUER_URL,
      audience: 'https://vercel.com/[TEAM_SLUG]',
      subject:
        'owner:[TEAM_SLUG]:project:[PROJECT_NAME]:environment:[ENVIRONMENT]',
    });

res.statusCode = 200;
    res.end('OK');
  } catch (error) {
    res.statusCode = 401;
    res.end('Unauthorized');
  }
});

server.listen(3000);
```

Make sure that you:

- Replace `[TEAM_SLUG]` with your team identifier from the Vercel's team URL
- Replace `[PROJECT_NAME]` with your [project's name](/content/docs/projects#project-name/index.html) in your [project's settings](/content/docs/projects#project-settings/index.html)
- Replace `[ENVIRONMENT]` with `development`, `preview`, `production`, or a [Custom Environment](/content/docs/deployments/environments#custom-environments/index.html) slug

### [Use the `getVercelOidcToken` function](/content/docs/oidc/api#use-the-getverceloidctoken-function/index.html)

Install the following package:

```bash
pnpm i @vercel/oidc
```

```bash
yarn add @vercel/oidc
```

```bash
npm i @vercel/oidc
```

```bash
bun add @vercel/oidc
```

In the code example below, the `getVercelOidcToken` function is used to retrieve the OIDC token from your Vercel environment. You can then use this token to authenticate the request to the external API.

```typescript
import { getVercelOidcToken } from '@vercel/oidc';

export const GET = async () => {
  const result = await fetch('https://api.example.com', {
    headers: {
      Authorization: `Bearer ${await getVercelOidcToken()}`,
    },
  });

return Response.json(await result.json());
};
```

### [Use a custom audience](/content/docs/oidc/api#use-a-custom-audience/index.html)

By default, the OIDC token's `aud` claim is set to `https://vercel.com/[TEAM_SLUG]`. If your API expects a different audience value, pass the `audience` option to `getVercelOidcToken`. This exchanges the default token for a new one with the custom `aud` claim.

```typescript
import { getVercelOidcToken } from '@vercel/oidc';

export const GET = async () => {
  const token = await getVercelOidcToken({
    audience: 'https://api.example.com',
  });

const result = await fetch('https://api.example.com', {
    headers: {
      Authorization: `Bearer ${token}`,
    },
  });

return Response.json(await result.json());
};
```

When validating the token on your API server, update the expected `audience` to match:

```typescript
const { payload } = await jose.jwtVerify(token, JWKS, {
  issuer: ISSUER_URL,
  audience: 'https://api.example.com',
});
```

Last updated September 17, 2026.
