🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

@vercel/oidc

Package Overview
Dependencies
Maintainers
2
Versions
24
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@vercel/oidc - npm Package Compare versions

Comparing version
3.1.0
to
3.2.0
+16
dist/auth-errors.d.ts
/**
* Error thrown when no authentication configuration is found.
* This typically means the user needs to log in.
*/
export declare class AccessTokenMissingError extends Error {
name: string;
constructor();
}
/**
* Error thrown when attempting to refresh the authentication token fails.
* This includes cases where no refresh token is available.
*/
export declare class RefreshAccessTokenFailedError extends Error {
name: string;
constructor(cause?: unknown);
}
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var auth_errors_exports = {};
__export(auth_errors_exports, {
AccessTokenMissingError: () => AccessTokenMissingError,
RefreshAccessTokenFailedError: () => RefreshAccessTokenFailedError
});
module.exports = __toCommonJS(auth_errors_exports);
class AccessTokenMissingError extends Error {
constructor() {
super(
"No authentication found. Please log in with the Vercel CLI (vercel login)."
);
this.name = "AccessTokenMissingError";
}
}
class RefreshAccessTokenFailedError extends Error {
constructor(cause) {
super("Failed to refresh authentication token.", { cause });
this.name = "RefreshAccessTokenFailedError";
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
AccessTokenMissingError,
RefreshAccessTokenFailedError
});
# Class: AccessTokenMissingError
Error thrown when no authentication configuration is found.
This typically means the user needs to log in.
## Hierarchy
- [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)
↳ **`AccessTokenMissingError`**
## Table of contents
### Constructors
- [constructor](AccessTokenMissingError.md#constructor)
### Properties
- [message](AccessTokenMissingError.md#message)
- [name](AccessTokenMissingError.md#name)
- [stack](AccessTokenMissingError.md#stack)
- [prepareStackTrace](AccessTokenMissingError.md#preparestacktrace)
- [stackTraceLimit](AccessTokenMissingError.md#stacktracelimit)
### Methods
- [captureStackTrace](AccessTokenMissingError.md#capturestacktrace)
## Constructors
### constructor
• **new AccessTokenMissingError**()
#### Overrides
Error.constructor
#### Defined in
[packages/oidc/src/auth-errors.ts:7](https://github.com/vercel/vercel/blob/main/packages/oidc/src/auth-errors.ts#L7)
## Properties
### message
• **message**: `string`
#### Inherited from
Error.message
#### Defined in
node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es5.d.ts:1054
---
### name
• **name**: `string` = `'AccessTokenMissingError'`
#### Overrides
Error.name
#### Defined in
[packages/oidc/src/auth-errors.ts:6](https://github.com/vercel/vercel/blob/main/packages/oidc/src/auth-errors.ts#L6)
---
### stack
• `Optional` **stack**: `string`
#### Inherited from
Error.stack
#### Defined in
node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es5.d.ts:1055
---
### prepareStackTrace
▪ `Static` `Optional` **prepareStackTrace**: (`err`: [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error), `stackTraces`: `CallSite`[]) => `any`
#### Type declaration
▸ (`err`, `stackTraces`): `any`
Optional override for formatting stack traces
**`See`**
https://v8.dev/docs/stack-trace-api#customizing-stack-traces
##### Parameters
| Name | Type |
| :------------ | :------------------------------------------------------------------------------------------------ |
| `err` | [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) |
| `stackTraces` | `CallSite`[] |
##### Returns
`any`
#### Inherited from
Error.prepareStackTrace
#### Defined in
node_modules/.pnpm/@types+node@20.11.0/node_modules/@types/node/globals.d.ts:28
---
### stackTraceLimit
▪ `Static` **stackTraceLimit**: `number`
#### Inherited from
Error.stackTraceLimit
#### Defined in
node_modules/.pnpm/@types+node@20.11.0/node_modules/@types/node/globals.d.ts:30
## Methods
### captureStackTrace
▸ `Static` **captureStackTrace**(`targetObject`, `constructorOpt?`): `void`
Create .stack property on a target object
#### Parameters
| Name | Type |
| :---------------- | :------------------------------------------------------------------------------------------------------ |
| `targetObject` | `object` |
| `constructorOpt?` | [`Function`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function) |
#### Returns
`void`
#### Inherited from
Error.captureStackTrace
#### Defined in
node_modules/.pnpm/@types+node@20.11.0/node_modules/@types/node/globals.d.ts:21
# Class: RefreshAccessTokenFailedError
Error thrown when attempting to refresh the authentication token fails.
This includes cases where no refresh token is available.
## Hierarchy
- [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)
↳ **`RefreshAccessTokenFailedError`**
## Table of contents
### Constructors
- [constructor](RefreshAccessTokenFailedError.md#constructor)
### Properties
- [message](RefreshAccessTokenFailedError.md#message)
- [name](RefreshAccessTokenFailedError.md#name)
- [stack](RefreshAccessTokenFailedError.md#stack)
- [prepareStackTrace](RefreshAccessTokenFailedError.md#preparestacktrace)
- [stackTraceLimit](RefreshAccessTokenFailedError.md#stacktracelimit)
### Methods
- [captureStackTrace](RefreshAccessTokenFailedError.md#capturestacktrace)
## Constructors
### constructor
• **new RefreshAccessTokenFailedError**(`cause?`)
#### Parameters
| Name | Type |
| :------- | :-------- |
| `cause?` | `unknown` |
#### Overrides
Error.constructor
#### Defined in
[packages/oidc/src/auth-errors.ts:20](https://github.com/vercel/vercel/blob/main/packages/oidc/src/auth-errors.ts#L20)
## Properties
### message
• **message**: `string`
#### Inherited from
Error.message
#### Defined in
node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es5.d.ts:1054
---
### name
• **name**: `string` = `'RefreshAccessTokenFailedError'`
#### Overrides
Error.name
#### Defined in
[packages/oidc/src/auth-errors.ts:19](https://github.com/vercel/vercel/blob/main/packages/oidc/src/auth-errors.ts#L19)
---
### stack
• `Optional` **stack**: `string`
#### Inherited from
Error.stack
#### Defined in
node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es5.d.ts:1055
---
### prepareStackTrace
▪ `Static` `Optional` **prepareStackTrace**: (`err`: [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error), `stackTraces`: `CallSite`[]) => `any`
#### Type declaration
▸ (`err`, `stackTraces`): `any`
Optional override for formatting stack traces
**`See`**
https://v8.dev/docs/stack-trace-api#customizing-stack-traces
##### Parameters
| Name | Type |
| :------------ | :------------------------------------------------------------------------------------------------ |
| `err` | [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) |
| `stackTraces` | `CallSite`[] |
##### Returns
`any`
#### Inherited from
Error.prepareStackTrace
#### Defined in
node_modules/.pnpm/@types+node@20.11.0/node_modules/@types/node/globals.d.ts:28
---
### stackTraceLimit
▪ `Static` **stackTraceLimit**: `number`
#### Inherited from
Error.stackTraceLimit
#### Defined in
node_modules/.pnpm/@types+node@20.11.0/node_modules/@types/node/globals.d.ts:30
## Methods
### captureStackTrace
▸ `Static` **captureStackTrace**(`targetObject`, `constructorOpt?`): `void`
Create .stack property on a target object
#### Parameters
| Name | Type |
| :---------------- | :------------------------------------------------------------------------------------------------------ |
| `targetObject` | `object` |
| `constructorOpt?` | [`Function`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function) |
#### Returns
`void`
#### Inherited from
Error.captureStackTrace
#### Defined in
node_modules/.pnpm/@types+node@20.11.0/node_modules/@types/node/globals.d.ts:21
+8
-0
# @vercel/oidc
## 3.2.0
### Minor Changes
- - Add optional `team` and `project` parameters to `getVercelOidcToken()` to allow explicit control over token refresh behavior instead of always reading from `.vercel/project.json` ([#14864](https://github.com/vercel/vercel/pull/14864))
- Add `expirationBufferMs` option to both `getVercelOidcToken()` and `getVercelToken()` to proactively refresh tokens before they expire (useful for avoiding auth errors mid-request)
- Export `getVercelToken()` function with `GetVercelTokenOptions` interface to allow refreshing CLI tokens with configurable expiration buffer
## 3.1.0

@@ -4,0 +12,0 @@

+1
-1

@@ -30,2 +30,2 @@ /**

*/
export declare function isValidAccessToken(authConfig: AuthConfig): boolean;
export declare function isValidAccessToken(authConfig: AuthConfig, expirationBufferMs?: number): boolean;

@@ -71,3 +71,3 @@ "use strict";

}
function isValidAccessToken(authConfig) {
function isValidAccessToken(authConfig, expirationBufferMs = 0) {
if (!authConfig.token)

@@ -78,3 +78,4 @@ return false;

const nowInSeconds = Math.floor(Date.now() / 1e3);
return authConfig.expiresAt >= nowInSeconds;
const bufferInSeconds = expirationBufferMs / 1e3;
return authConfig.expiresAt >= nowInSeconds + bufferInSeconds;
}

@@ -81,0 +82,0 @@ // Annotate the CommonJS export names for ESM import in node:

/**
* Options for getting the Vercel OIDC token.
*/
export interface GetVercelOidcTokenOptions {
/**
* Optional team ID (team_*) or slug to use for token refresh.
* When provided, this team will be used instead of reading from `.vercel/project.json`.
*/
team?: string;
/**
* Optional project ID (prj_*) or slug to use for token refresh.
* When provided, this project will be used instead of reading from `.vercel/project.json`.
*/
project?: string;
/**
* Optional time buffer in milliseconds before token expiry to consider it expired.
* When provided, the token will be refreshed if it expires within this buffer time.
* @default 0
*/
expirationBufferMs?: number;
}
/**
* Gets the current OIDC token from the request context or the environment variable.

@@ -11,2 +32,3 @@ *

*
* @param {GetVercelOidcTokenOptions} [options] - Optional configuration for token retrieval.
* @returns {Promise<string>} A promise that resolves to the OIDC token.

@@ -27,4 +49,15 @@ * @throws {Error} If the `x-vercel-oidc-token` header is missing from the request context and the environment variable `VERCEL_OIDC_TOKEN` is not set. If the token

* ```
*
* @example
*
* ```js
* // Using the OIDC token with explicit team and project (supports IDs and slugs)
* getVercelOidcToken({ team: 'my-team', project: 'my-project' }).then((token) => {
* console.log('OIDC Token:', token);
* }).catch((error) => {
* console.error('Error:', error.message);
* });
* ```
*/
export declare function getVercelOidcToken(): Promise<string>;
export declare function getVercelOidcToken(options?: GetVercelOidcTokenOptions): Promise<string>;
/**

@@ -31,0 +64,0 @@ * Gets the current OIDC token from the request context or the environment variable.

@@ -37,3 +37,3 @@ "use strict";

var import_token_error = require("./token-error");
async function getVercelOidcToken() {
async function getVercelOidcToken(options) {
let token = "";

@@ -51,4 +51,4 @@ let err;

]);
if (!token || isExpired(getTokenPayload(token))) {
await refreshToken();
if (!token || isExpired(getTokenPayload(token), options?.expirationBufferMs)) {
await refreshToken(options);
token = getVercelOidcTokenSync();

@@ -55,0 +55,0 @@ }

@@ -41,4 +41,4 @@ "use strict";

let tokenDataDir;
const projectId = "test-project-id";
const teamId = "test-team-id";
const projectId = "prj_test123";
const teamId = "team_test456";
(0, import_vitest.beforeEach)(() => {

@@ -67,3 +67,3 @@ import_vitest.vi.clearAllMocks();

});
(0, import_vitest.test)("should throw helpful error when CLI auth file is missing", async () => {
(0, import_vitest.test)("should throw AccessTokenMissingError when CLI auth file is missing", async () => {
fs.writeFileSync(

@@ -75,3 +75,3 @@ path.join(rootDir, ".vercel", "project.json"),

await (0, import_vitest.expect)((0, import_get_vercel_oidc_token.getVercelOidcToken)()).rejects.toThrow(
/Failed to refresh OIDC token: Log in to Vercel CLI and link your project with `vc link`/
/No authentication found/
);

@@ -222,2 +222,120 @@ });

});
(0, import_vitest.test)("should use provided team and project for refresh instead of reading project.json", async () => {
const customProjectId = "prj_custom123";
const customTeamId = "team_custom456";
fs.writeFileSync(
path.join(cliDataDir, "auth.json"),
JSON.stringify({ token: "test-auth-token" })
);
const newToken = createValidToken("custom-token");
const getVercelOidcTokenSpy = import_vitest.vi.spyOn(tokenUtil, "getVercelOidcToken").mockResolvedValue({
token: newToken
});
import_vitest.vi.spyOn(tokenUtil, "getTokenPayload").mockReturnValueOnce({
sub: "test-sub",
name: "test-name",
exp: Date.now() / 1e3 - 1e3
}).mockReturnValue({
sub: "test-sub",
name: "test-name",
exp: Date.now() / 1e3 + 43200
});
process.env.VERCEL_OIDC_TOKEN = createExpiredToken();
const token = await (0, import_get_vercel_oidc_token.getVercelOidcToken)({
team: customTeamId,
project: customProjectId
});
(0, import_vitest.expect)(token).toBe(newToken);
(0, import_vitest.expect)(getVercelOidcTokenSpy).toHaveBeenCalledWith(
"test-auth-token",
customProjectId,
customTeamId
);
});
(0, import_vitest.test)("should use provided project and read team from project.json", async () => {
const customProjectId = "prj_custom234";
fs.writeFileSync(
path.join(cliDataDir, "auth.json"),
JSON.stringify({ token: "test-auth-token" })
);
fs.writeFileSync(
path.join(rootDir, ".vercel", "project.json"),
JSON.stringify({ projectId: "original-project-id", orgId: teamId })
);
const newToken = createValidToken("partial-custom-token");
const getVercelOidcTokenSpy = import_vitest.vi.spyOn(tokenUtil, "getVercelOidcToken").mockResolvedValue({
token: newToken
});
import_vitest.vi.spyOn(tokenUtil, "getTokenPayload").mockReturnValueOnce({
sub: "test-sub",
name: "test-name",
exp: Date.now() / 1e3 - 1e3
}).mockReturnValue({
sub: "test-sub",
name: "test-name",
exp: Date.now() / 1e3 + 43200
});
process.env.VERCEL_OIDC_TOKEN = createExpiredToken();
const token = await (0, import_get_vercel_oidc_token.getVercelOidcToken)({
project: customProjectId
});
(0, import_vitest.expect)(token).toBe(newToken);
(0, import_vitest.expect)(getVercelOidcTokenSpy).toHaveBeenCalledWith(
"test-auth-token",
customProjectId,
teamId
);
});
(0, import_vitest.test)("should use provided team and read project from project.json", async () => {
const customTeamId = "team_custom789";
fs.writeFileSync(
path.join(cliDataDir, "auth.json"),
JSON.stringify({ token: "test-auth-token" })
);
fs.writeFileSync(
path.join(rootDir, ".vercel", "project.json"),
JSON.stringify({ projectId, orgId: "original-team-id" })
);
const newToken = createValidToken("partial-custom-token-2");
const getVercelOidcTokenSpy = import_vitest.vi.spyOn(tokenUtil, "getVercelOidcToken").mockResolvedValue({
token: newToken
});
import_vitest.vi.spyOn(tokenUtil, "getTokenPayload").mockReturnValueOnce({
sub: "test-sub",
name: "test-name",
exp: Date.now() / 1e3 - 1e3
}).mockReturnValue({
sub: "test-sub",
name: "test-name",
exp: Date.now() / 1e3 + 43200
});
process.env.VERCEL_OIDC_TOKEN = createExpiredToken();
const token = await (0, import_get_vercel_oidc_token.getVercelOidcToken)({
team: customTeamId
});
(0, import_vitest.expect)(token).toBe(newToken);
(0, import_vitest.expect)(getVercelOidcTokenSpy).toHaveBeenCalledWith(
"test-auth-token",
projectId,
customTeamId
);
});
(0, import_vitest.test)("should not refresh when token is valid even with options provided", async () => {
const validToken = createValidToken();
process.env.VERCEL_OIDC_TOKEN = validToken;
const getVercelOidcTokenSpy = import_vitest.vi.spyOn(tokenUtil, "getVercelOidcToken").mockResolvedValue({
token: "should-not-be-called"
});
import_vitest.vi.spyOn(tokenUtil, "getTokenPayload").mockReturnValue({
sub: "test-sub",
name: "test-name",
exp: Date.now() / 1e3 + 43200
});
const token = await (0, import_get_vercel_oidc_token.getVercelOidcToken)({
team: "custom-team",
project: "custom-project"
});
(0, import_vitest.expect)(token).toBe(validToken);
(0, import_vitest.expect)(getVercelOidcTokenSpy).not.toHaveBeenCalled();
});
});

@@ -224,0 +342,0 @@ function createExpiredToken() {

export { getContext } from './get-context';
export { AccessTokenMissingError, RefreshAccessTokenFailedError, } from './auth-errors';
export declare function getVercelOidcToken(): Promise<string>;
export declare function getVercelOidcTokenSync(): string;
export declare function getVercelToken(): Promise<string>;

@@ -21,8 +21,12 @@ "use strict";

__export(index_browser_exports, {
AccessTokenMissingError: () => import_auth_errors.AccessTokenMissingError,
RefreshAccessTokenFailedError: () => import_auth_errors.RefreshAccessTokenFailedError,
getContext: () => import_get_context.getContext,
getVercelOidcToken: () => getVercelOidcToken,
getVercelOidcTokenSync: () => getVercelOidcTokenSync
getVercelOidcTokenSync: () => getVercelOidcTokenSync,
getVercelToken: () => getVercelToken
});
module.exports = __toCommonJS(index_browser_exports);
var import_get_context = require("./get-context");
var import_auth_errors = require("./auth-errors");
async function getVercelOidcToken() {

@@ -34,7 +38,13 @@ return "";

}
async function getVercelToken() {
throw new Error("getVercelToken is not supported in browser environments");
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
AccessTokenMissingError,
RefreshAccessTokenFailedError,
getContext,
getVercelOidcToken,
getVercelOidcTokenSync
getVercelOidcTokenSync,
getVercelToken
});
export { getVercelOidcToken, getVercelOidcTokenSync, } from './get-vercel-oidc-token';
export { getContext } from './get-context';
export { AccessTokenMissingError, RefreshAccessTokenFailedError, } from './auth-errors';
export { getVercelToken } from './token-util';

@@ -21,5 +21,8 @@ "use strict";

__export(src_exports, {
AccessTokenMissingError: () => import_auth_errors.AccessTokenMissingError,
RefreshAccessTokenFailedError: () => import_auth_errors.RefreshAccessTokenFailedError,
getContext: () => import_get_context.getContext,
getVercelOidcToken: () => import_get_vercel_oidc_token.getVercelOidcToken,
getVercelOidcTokenSync: () => import_get_vercel_oidc_token.getVercelOidcTokenSync
getVercelOidcTokenSync: () => import_get_vercel_oidc_token.getVercelOidcTokenSync,
getVercelToken: () => import_token_util.getVercelToken
});

@@ -29,7 +32,12 @@ module.exports = __toCommonJS(src_exports);

var import_get_context = require("./get-context");
var import_auth_errors = require("./auth-errors");
var import_token_util = require("./token-util");
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
AccessTokenMissingError,
RefreshAccessTokenFailedError,
getContext,
getVercelOidcToken,
getVercelOidcTokenSync
getVercelOidcTokenSync,
getVercelToken
});
export declare function getVercelDataDir(): string | null;
export declare function getVercelCliToken(): Promise<string | null>;
export interface GetVercelTokenOptions {
/**
* Optional time buffer in milliseconds before token expiry to consider it expired.
* When provided, the token will be refreshed if it expires within this buffer time.
* @default 0
*/
expirationBufferMs?: number;
}
export declare function getVercelToken(options?: GetVercelTokenOptions): Promise<string>;
interface VercelTokenResponse {

@@ -20,3 +28,3 @@ token: string;

export declare function getTokenPayload(token: string): TokenPayload;
export declare function isExpired(token: TokenPayload): boolean;
export declare function isExpired(token: TokenPayload, bufferMs?: number): boolean;
export {};

@@ -34,5 +34,5 @@ "use strict";

getTokenPayload: () => getTokenPayload,
getVercelCliToken: () => getVercelCliToken,
getVercelDataDir: () => getVercelDataDir,
getVercelOidcToken: () => getVercelOidcToken,
getVercelToken: () => getVercelToken,
isExpired: () => isExpired,

@@ -49,2 +49,3 @@ loadToken: () => loadToken,

var import_oauth = require("./oauth");
var import_auth_errors = require("./auth-errors");
function getVercelDataDir() {

@@ -58,13 +59,13 @@ const vercelFolder = "com.vercel.cli";

}
async function getVercelCliToken() {
async function getVercelToken(options) {
const authConfig = (0, import_auth_config.readAuthConfig)();
if (!authConfig) {
return null;
if (!authConfig?.token) {
throw new import_auth_errors.AccessTokenMissingError();
}
if ((0, import_auth_config.isValidAccessToken)(authConfig)) {
return authConfig.token || null;
if ((0, import_auth_config.isValidAccessToken)(authConfig, options?.expirationBufferMs)) {
return authConfig.token;
}
if (!authConfig.refreshToken) {
(0, import_auth_config.writeAuthConfig)({});
return null;
throw new import_auth_errors.RefreshAccessTokenFailedError("No refresh token available");
}

@@ -78,3 +79,3 @@ try {

(0, import_auth_config.writeAuthConfig)({});
return null;
throw new import_auth_errors.RefreshAccessTokenFailedError(tokensError);
}

@@ -89,6 +90,9 @@ const updatedConfig = {

(0, import_auth_config.writeAuthConfig)(updatedConfig);
return updatedConfig.token ?? null;
return updatedConfig.token;
} catch (error) {
(0, import_auth_config.writeAuthConfig)({});
return null;
if (error instanceof import_auth_errors.AccessTokenMissingError || error instanceof import_auth_errors.RefreshAccessTokenFailedError) {
throw error;
}
throw new import_auth_errors.RefreshAccessTokenFailedError(error);
}

@@ -189,4 +193,4 @@ }

}
function isExpired(token) {
return token.exp * 1e3 < Date.now();
function isExpired(token, bufferMs = 0) {
return token.exp * 1e3 < Date.now() + bufferMs;
}

@@ -198,5 +202,5 @@ // Annotate the CommonJS export names for ESM import in node:

getTokenPayload,
getVercelCliToken,
getVercelDataDir,
getVercelOidcToken,
getVercelToken,
isExpired,

@@ -203,0 +207,0 @@ loadToken,

@@ -28,2 +28,3 @@ "use strict";

var oauth = __toESM(require("./oauth"));
var import_auth_errors = require("./auth-errors");
import_vitest.vi.mock("fs");

@@ -34,3 +35,3 @@ import_vitest.vi.mock("./token-io", () => ({

}));
(0, import_vitest.describe)("getVercelCliToken", () => {
(0, import_vitest.describe)("getVercelToken", () => {
(0, import_vitest.beforeEach)(() => {

@@ -52,10 +53,9 @@ import_vitest.vi.clearAllMocks();

});
const token = await (0, import_token_util.getVercelCliToken)();
const token = await (0, import_token_util.getVercelToken)();
(0, import_vitest.expect)(token).toBe("valid-access-token");
(0, import_vitest.expect)(authConfig.writeAuthConfig).not.toHaveBeenCalled();
});
(0, import_vitest.it)("should return null if auth config does not exist", async () => {
(0, import_vitest.it)("should throw AccessTokenMissingError if auth config does not exist", async () => {
import_vitest.vi.spyOn(authConfig, "readAuthConfig").mockReturnValue(null);
const token = await (0, import_token_util.getVercelCliToken)();
(0, import_vitest.expect)(token).toBeNull();
await (0, import_vitest.expect)((0, import_token_util.getVercelToken)()).rejects.toThrow(import_auth_errors.AccessTokenMissingError);
});

@@ -82,3 +82,3 @@ (0, import_vitest.it)("should refresh token if expired and refresh token exists", async () => {

import_vitest.vi.spyOn(oauth, "refreshTokenRequest").mockResolvedValue(mockResponse);
const token = await (0, import_token_util.getVercelCliToken)();
const token = await (0, import_token_util.getVercelToken)();
(0, import_vitest.expect)(token).toBe("new-access-token");

@@ -96,3 +96,3 @@ (0, import_vitest.expect)(oauth.refreshTokenRequest).toHaveBeenCalledWith({

});
(0, import_vitest.it)("should clear auth and return null if token expired and no refresh token", async () => {
(0, import_vitest.it)("should clear auth and throw RefreshAccessTokenFailedError if token expired and no refresh token", async () => {
const expiredTokenNoRefresh = {

@@ -107,7 +107,8 @@ token: "expired-access-token",

});
const token = await (0, import_token_util.getVercelCliToken)();
(0, import_vitest.expect)(token).toBeNull();
await (0, import_vitest.expect)((0, import_token_util.getVercelToken)()).rejects.toThrow(
import_auth_errors.RefreshAccessTokenFailedError
);
(0, import_vitest.expect)(authConfig.writeAuthConfig).toHaveBeenCalledWith({});
});
(0, import_vitest.it)("should clear auth if refresh fails with OAuth error", async () => {
(0, import_vitest.it)("should clear auth and throw RefreshAccessTokenFailedError if refresh fails with OAuth error", async () => {
const expiredToken = {

@@ -129,7 +130,8 @@ token: "expired-access-token",

import_vitest.vi.spyOn(oauth, "refreshTokenRequest").mockResolvedValue(mockErrorResponse);
const token = await (0, import_token_util.getVercelCliToken)();
(0, import_vitest.expect)(token).toBeNull();
await (0, import_vitest.expect)((0, import_token_util.getVercelToken)()).rejects.toThrow(
import_auth_errors.RefreshAccessTokenFailedError
);
(0, import_vitest.expect)(authConfig.writeAuthConfig).toHaveBeenCalledWith({});
});
(0, import_vitest.it)("should clear auth if refresh fails with network error", async () => {
(0, import_vitest.it)("should clear auth and throw RefreshAccessTokenFailedError if refresh fails with network error", async () => {
const expiredToken = {

@@ -146,4 +148,5 @@ token: "expired-access-token",

);
const token = await (0, import_token_util.getVercelCliToken)();
(0, import_vitest.expect)(token).toBeNull();
await (0, import_vitest.expect)((0, import_token_util.getVercelToken)()).rejects.toThrow(
import_auth_errors.RefreshAccessTokenFailedError
);
(0, import_vitest.expect)(authConfig.writeAuthConfig).toHaveBeenCalledWith({});

@@ -158,3 +161,3 @@ });

});
const token = await (0, import_token_util.getVercelCliToken)();
const token = await (0, import_token_util.getVercelToken)();
(0, import_vitest.expect)(token).toBe("cli-provided-token");

@@ -182,3 +185,3 @@ (0, import_vitest.expect)(authConfig.writeAuthConfig).not.toHaveBeenCalled();

import_vitest.vi.spyOn(oauth, "refreshTokenRequest").mockResolvedValue(mockResponse);
await (0, import_token_util.getVercelCliToken)();
await (0, import_token_util.getVercelToken)();
(0, import_vitest.expect)(authConfig.writeAuthConfig).toHaveBeenCalledWith(

@@ -209,3 +212,3 @@ import_vitest.expect.objectContaining({

import_vitest.vi.spyOn(oauth, "refreshTokenRequest").mockResolvedValue(mockResponse);
await (0, import_token_util.getVercelCliToken)();
await (0, import_token_util.getVercelToken)();
const writeCall = import_vitest.vi.mocked(authConfig.writeAuthConfig).mock.calls[0][0];

@@ -234,3 +237,3 @@ (0, import_vitest.expect)(writeCall).not.toHaveProperty("refreshToken");

const beforeCall = Math.floor(Date.now() / 1e3);
await (0, import_token_util.getVercelCliToken)();
await (0, import_token_util.getVercelToken)();
const afterCall = Math.floor(Date.now() / 1e3);

@@ -237,0 +240,0 @@ const writeCall = import_vitest.vi.mocked(authConfig.writeAuthConfig).mock.calls[0][0];

@@ -1,1 +0,19 @@

export declare function refreshToken(): Promise<void>;
export interface RefreshTokenOptions {
/**
* Team ID (team_*) or slug to use for token refresh.
* When provided, this team will be used instead of reading from `.vercel/project.json`.
*/
team?: string;
/**
* Project ID (prj_*) or slug to use for token refresh.
* When provided, this project will be used instead of reading from `.vercel/project.json`.
*/
project?: string;
/**
* Optional time buffer in milliseconds before token expiry to consider it expired.
* When provided, the token will be refreshed if it expires within this buffer time.
* @default 0
*/
expirationBufferMs?: number;
}
export declare function refreshToken(options?: RefreshTokenOptions): Promise<void>;

@@ -26,17 +26,24 @@ "use strict";

var import_token_util = require("./token-util");
async function refreshToken() {
const { projectId, teamId } = (0, import_token_util.findProjectInfo)();
async function refreshToken(options) {
let projectId = options?.project;
let teamId = options?.team;
if (!projectId && !teamId) {
const projectInfo = (0, import_token_util.findProjectInfo)();
projectId = projectInfo.projectId;
teamId = projectInfo.teamId;
} else if (!projectId || !teamId) {
const projectInfo = (0, import_token_util.findProjectInfo)();
projectId = projectId ?? projectInfo.projectId;
teamId = teamId ?? projectInfo.teamId;
}
if (!projectId) {
throw new import_token_error.VercelOidcTokenError(
"Failed to refresh OIDC token: No project specified. Try re-linking your project with `vc link`"
);
}
let maybeToken = (0, import_token_util.loadToken)(projectId);
if (!maybeToken || (0, import_token_util.isExpired)((0, import_token_util.getTokenPayload)(maybeToken.token))) {
const authToken = await (0, import_token_util.getVercelCliToken)();
if (!authToken) {
throw new import_token_error.VercelOidcTokenError(
"Failed to refresh OIDC token: Log in to Vercel CLI and link your project with `vc link`"
);
}
if (!projectId) {
throw new import_token_error.VercelOidcTokenError(
"Failed to refresh OIDC token: Try re-linking your project with `vc link`"
);
}
if (!maybeToken || (0, import_token_util.isExpired)((0, import_token_util.getTokenPayload)(maybeToken.token), options?.expirationBufferMs)) {
const authToken = await (0, import_token_util.getVercelToken)({
expirationBufferMs: options?.expirationBufferMs
});
maybeToken = await (0, import_token_util.getVercelOidcToken)(authToken, projectId, teamId);

@@ -43,0 +50,0 @@ if (!maybeToken) {

@@ -38,3 +38,3 @@ "use strict";

let tokenDataDir;
const projectId = "test-project-id";
const projectId = "prj_test123";
(0, import_vitest.beforeEach)(() => {

@@ -61,3 +61,3 @@ import_vitest.vi.clearAllMocks();

import_vitest.vi.mocked(import_token_io.getUserDataDir).mockReturnValue(userDataDir);
import_vitest.vi.spyOn(tokenUtil, "getVercelCliToken").mockResolvedValue("test");
import_vitest.vi.spyOn(tokenUtil, "getVercelToken").mockResolvedValue("test");
import_vitest.vi.spyOn(tokenUtil, "getVercelOidcToken").mockResolvedValue({

@@ -86,2 +86,108 @@ token: "test-token"

});
(0, import_vitest.test)("should use provided team and project instead of reading project.json", async () => {
const customProjectId = "prj_custom123";
const customTeamId = "team_custom456";
const getVercelOidcTokenSpy = import_vitest.vi.spyOn(tokenUtil, "getVercelOidcToken");
const findRootDirSpy = import_vitest.vi.mocked(import_token_io.findRootDir);
await (0, import_token.refreshToken)({ team: customTeamId, project: customProjectId });
(0, import_vitest.expect)(findRootDirSpy).not.toHaveBeenCalled();
(0, import_vitest.expect)(getVercelOidcTokenSpy).toHaveBeenCalledWith(
"test",
customProjectId,
customTeamId
);
const tokenPath = path.join(tokenDataDir, `${customProjectId}.json`);
(0, import_vitest.expect)(fs.existsSync(tokenPath)).toBe(true);
const savedToken = JSON.parse(fs.readFileSync(tokenPath, "utf8"));
(0, import_vitest.expect)(savedToken).toEqual({ token: "test-token" });
});
(0, import_vitest.test)("should merge provided project with team from project.json", async () => {
const customProjectId = "prj_custom234";
const projectTeamId = "team_fromproject567";
fs.writeFileSync(
path.join(rootDir, ".vercel", "project.json"),
JSON.stringify({ projectId, orgId: projectTeamId })
);
const getVercelOidcTokenSpy = import_vitest.vi.spyOn(tokenUtil, "getVercelOidcToken");
await (0, import_token.refreshToken)({ project: customProjectId });
(0, import_vitest.expect)(getVercelOidcTokenSpy).toHaveBeenCalledWith(
"test",
customProjectId,
projectTeamId
);
});
(0, import_vitest.test)("should merge provided team with project from project.json", async () => {
const customTeamId = "team_custom789";
const projectProjectId = "prj_fromjson123";
fs.writeFileSync(
path.join(rootDir, ".vercel", "project.json"),
JSON.stringify({ projectId: projectProjectId, orgId: "original-team" })
);
const getVercelOidcTokenSpy = import_vitest.vi.spyOn(tokenUtil, "getVercelOidcToken");
await (0, import_token.refreshToken)({ team: customTeamId });
(0, import_vitest.expect)(getVercelOidcTokenSpy).toHaveBeenCalledWith(
"test",
projectProjectId,
customTeamId
);
});
(0, import_vitest.test)("should use cached token when valid with custom project", async () => {
const customProjectId = "prj_customcached123";
const customTeamId = "team_customcached456";
const cachedToken = { token: "cached-valid-token" };
const tokenPath = path.join(tokenDataDir, `${customProjectId}.json`);
fs.writeFileSync(tokenPath, JSON.stringify(cachedToken));
const getVercelOidcTokenSpy = import_vitest.vi.spyOn(tokenUtil, "getVercelOidcToken");
await (0, import_token.refreshToken)({ team: customTeamId, project: customProjectId });
(0, import_vitest.expect)(getVercelOidcTokenSpy).not.toHaveBeenCalled();
(0, import_vitest.expect)(process.env.VERCEL_OIDC_TOKEN).toBe("cached-valid-token");
});
(0, import_vitest.test)("should refresh token when cached token expires within buffer", async () => {
const customProjectId = "prj_buffertest123";
const customTeamId = "team_buffertest456";
const cachedToken = { token: "expiring-soon-token" };
const tokenPath = path.join(tokenDataDir, `${customProjectId}.json`);
fs.writeFileSync(tokenPath, JSON.stringify(cachedToken));
const expiresIn3Minutes = Math.floor((Date.now() + 18e4) / 1e3);
import_vitest.vi.spyOn(tokenUtil, "getTokenPayload").mockReturnValue({
sub: "test-sub",
name: "test-name",
exp: expiresIn3Minutes
});
const getVercelOidcTokenSpy = import_vitest.vi.spyOn(tokenUtil, "getVercelOidcToken").mockResolvedValue({ token: "fresh-token" });
await (0, import_token.refreshToken)({
team: customTeamId,
project: customProjectId,
expirationBufferMs: 3e5
});
(0, import_vitest.expect)(getVercelOidcTokenSpy).toHaveBeenCalledWith(
"test",
customProjectId,
customTeamId
);
(0, import_vitest.expect)(process.env.VERCEL_OIDC_TOKEN).toBe("fresh-token");
const savedToken = JSON.parse(fs.readFileSync(tokenPath, "utf8"));
(0, import_vitest.expect)(savedToken).toEqual({ token: "fresh-token" });
});
(0, import_vitest.test)("should use cached token when it does not expire within buffer", async () => {
const customProjectId = "prj_buffervalid123";
const customTeamId = "team_buffervalid456";
const cachedToken = { token: "valid-cached-token" };
const tokenPath = path.join(tokenDataDir, `${customProjectId}.json`);
fs.writeFileSync(tokenPath, JSON.stringify(cachedToken));
const expiresIn10Minutes = Math.floor((Date.now() + 6e5) / 1e3);
import_vitest.vi.spyOn(tokenUtil, "getTokenPayload").mockReturnValue({
sub: "test-sub",
name: "test-name",
exp: expiresIn10Minutes
});
const getVercelOidcTokenSpy = import_vitest.vi.spyOn(tokenUtil, "getVercelOidcToken");
await (0, import_token.refreshToken)({
team: customTeamId,
project: customProjectId,
expirationBufferMs: 3e5
});
(0, import_vitest.expect)(getVercelOidcTokenSpy).not.toHaveBeenCalled();
(0, import_vitest.expect)(process.env.VERCEL_OIDC_TOKEN).toBe("valid-cached-token");
});
});

@@ -5,2 +5,7 @@ # @vercel/oidc

### Classes
- [AccessTokenMissingError](classes/AccessTokenMissingError.md)
- [RefreshAccessTokenFailedError](classes/RefreshAccessTokenFailedError.md)
### Functions

@@ -11,2 +16,3 @@

- [getVercelOidcTokenSync](README.md#getverceloidctokensync)
- [getVercelToken](README.md#getverceltoken)

@@ -25,3 +31,3 @@ ## Functions

[get-context.ts:7](https://github.com/vercel/vercel/blob/main/packages/oidc/src/get-context.ts#L7)
[packages/oidc/src/get-context.ts:7](https://github.com/vercel/vercel/blob/main/packages/oidc/src/get-context.ts#L7)

@@ -32,3 +38,3 @@ ---

▸ **getVercelOidcToken**(): [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)<`string`\>
▸ **getVercelOidcToken**(`options?`): [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)<`string`\>

@@ -63,2 +69,21 @@ Gets the current OIDC token from the request context or the environment variable.

**`Example`**
```js
// Using the OIDC token with explicit team and project (supports IDs and slugs)
getVercelOidcToken({ team: 'my-team', project: 'my-project' })
.then(token => {
console.log('OIDC Token:', token);
})
.catch(error => {
console.error('Error:', error.message);
});
```
#### Parameters
| Name | Type | Description |
| :--------- | :-------------------------- | :------------------------------------------ |
| `options?` | `GetVercelOidcTokenOptions` | Optional configuration for token retrieval. |
#### Returns

@@ -72,3 +97,3 @@

[get-vercel-oidc-token.ts:30](https://github.com/vercel/vercel/blob/main/packages/oidc/src/get-vercel-oidc-token.ts#L30)
[packages/oidc/src/get-vercel-oidc-token.ts:64](https://github.com/vercel/vercel/blob/main/packages/oidc/src/get-vercel-oidc-token.ts#L64)

@@ -110,2 +135,22 @@ ---

[get-vercel-oidc-token.ts:85](https://github.com/vercel/vercel/blob/main/packages/oidc/src/get-vercel-oidc-token.ts#L85)
[packages/oidc/src/get-vercel-oidc-token.ts:124](https://github.com/vercel/vercel/blob/main/packages/oidc/src/get-vercel-oidc-token.ts#L124)
---
### getVercelToken
▸ **getVercelToken**(`options?`): [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)<`string`\>
#### Parameters
| Name | Type |
| :--------- | :---------------------- |
| `options?` | `GetVercelTokenOptions` |
#### Returns
[`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)<`string`\>
#### Defined in
[packages/oidc/src/token-util.ts:35](https://github.com/vercel/vercel/blob/main/packages/oidc/src/token-util.ts#L35)

@@ -20,3 +20,3 @@ {

},
"version": "3.1.0",
"version": "3.2.0",
"repository": {

@@ -23,0 +23,0 @@ "directory": "packages/oidc",

# `@vercel/oidc`
Runtime OIDC helper methods intended to be used with your Vercel Functions
## Usage
### Getting an OIDC Token
```typescript
import { getVercelOidcToken } from '@vercel/oidc';
// Get token using project.json configuration
const token = await getVercelOidcToken();
// Get token with explicit project and team (supports both IDs and slugs)
const token = await getVercelOidcToken({
project: 'my-project', // or 'prj_abc123'
team: 'my-team', // or 'team_xyz789'
});
// Get token with expiration buffer (refresh if expires within 5 minutes)
const token = await getVercelOidcToken({
expirationBufferMs: 5 * 60 * 1000,
});
```
## API
### `getVercelOidcToken(options?)`
Gets the current OIDC token from the request context or environment variable. Will refresh the token if expired in development.
**Options:**
- `project?: string` - Project ID (prj\_\*) or slug
- `team?: string` - Team ID (team\_\*) or slug
- `expirationBufferMs?: number` - Buffer time in ms before expiry to trigger refresh (default: 0)
### `getVercelOidcTokenSync()`
Synchronously gets the current OIDC token without refreshing. Use `getVercelOidcToken()` if you need automatic refresh in development.