@vercel/oidc
Advanced tools
| /** | ||
| * 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 @@ |
@@ -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 | ||
| }); |
+2
-0
| export { getVercelOidcToken, getVercelOidcTokenSync, } from './get-vercel-oidc-token'; | ||
| export { getContext } from './get-context'; | ||
| export { AccessTokenMissingError, RefreshAccessTokenFailedError, } from './auth-errors'; | ||
| export { getVercelToken } from './token-util'; |
+10
-2
@@ -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 | ||
| }); |
+10
-2
| 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 {}; |
+17
-13
@@ -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, |
+22
-19
@@ -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]; |
+19
-1
@@ -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>; |
+21
-14
@@ -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) { |
+108
-2
@@ -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"); | ||
| }); | ||
| }); |
+49
-4
@@ -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) |
+1
-1
@@ -20,3 +20,3 @@ { | ||
| }, | ||
| "version": "3.1.0", | ||
| "version": "3.2.0", | ||
| "repository": { | ||
@@ -23,0 +23,0 @@ "directory": "packages/oidc", |
+38
-0
| # `@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. |
104725
35.21%37
12.12%1836
26.01%42
950%35
25%