@vercel/oidc 3.1.0 → 3.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +38 -0
- package/dist/auth-config.d.ts +1 -1
- package/dist/auth-config.js +4 -3
- package/dist/auth-errors.d.ts +16 -0
- package/dist/auth-errors.js +43 -0
- package/dist/get-vercel-oidc-token.d.ts +34 -1
- package/dist/get-vercel-oidc-token.js +3 -3
- package/dist/get-vercel-oidc-token.test.js +122 -4
- package/dist/index-browser.d.ts +2 -0
- package/dist/index-browser.js +12 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +10 -2
- package/dist/token-io.js +1 -1
- package/dist/token-util.d.ts +10 -2
- package/dist/token-util.js +17 -13
- package/dist/token-util.test.js +22 -19
- package/dist/token.d.ts +19 -1
- package/dist/token.js +21 -14
- package/dist/token.test.js +108 -2
- package/docs/README.md +49 -4
- package/docs/classes/AccessTokenMissingError.md +160 -0
- package/docs/classes/RefreshAccessTokenFailedError.md +166 -0
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @vercel/oidc
|
|
2
2
|
|
|
3
|
+
## 3.2.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Pin `typedoc-plugin-markdown` to `3.15.2` and `typedoc-plugin-mdn-links` to `3.0.3` to match the version used by `@vercel/edge`. The previous `4.1.2` version requires `typedoc@0.26.x` as a peer dependency but was paired with `typedoc@0.24.6`, which caused CI failures whenever pnpm hoisted the 4.x plugin (the plugin calls `app.internationalization.addTranslations`, which does not exist in typedoc 0.24). The choice of which plugin version got hoisted was non-deterministic, which is why the failure appeared as flaky `Build @vercel/<pkg>` steps in CI. ([#16072](https://github.com/vercel/vercel/pull/16072))
|
|
8
|
+
|
|
9
|
+
## 3.2.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- - 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))
|
|
14
|
+
- Add `expirationBufferMs` option to both `getVercelOidcToken()` and `getVercelToken()` to proactively refresh tokens before they expire (useful for avoiding auth errors mid-request)
|
|
15
|
+
- Export `getVercelToken()` function with `GetVercelTokenOptions` interface to allow refreshing CLI tokens with configurable expiration buffer
|
|
16
|
+
|
|
3
17
|
## 3.1.0
|
|
4
18
|
|
|
5
19
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -1,3 +1,41 @@
|
|
|
1
1
|
# `@vercel/oidc`
|
|
2
2
|
|
|
3
3
|
Runtime OIDC helper methods intended to be used with your Vercel Functions
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
### Getting an OIDC Token
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import { getVercelOidcToken } from '@vercel/oidc';
|
|
11
|
+
|
|
12
|
+
// Get token using project.json configuration
|
|
13
|
+
const token = await getVercelOidcToken();
|
|
14
|
+
|
|
15
|
+
// Get token with explicit project and team (supports both IDs and slugs)
|
|
16
|
+
const token = await getVercelOidcToken({
|
|
17
|
+
project: 'my-project', // or 'prj_abc123'
|
|
18
|
+
team: 'my-team', // or 'team_xyz789'
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// Get token with expiration buffer (refresh if expires within 5 minutes)
|
|
22
|
+
const token = await getVercelOidcToken({
|
|
23
|
+
expirationBufferMs: 5 * 60 * 1000,
|
|
24
|
+
});
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## API
|
|
28
|
+
|
|
29
|
+
### `getVercelOidcToken(options?)`
|
|
30
|
+
|
|
31
|
+
Gets the current OIDC token from the request context or environment variable. Will refresh the token if expired in development.
|
|
32
|
+
|
|
33
|
+
**Options:**
|
|
34
|
+
|
|
35
|
+
- `project?: string` - Project ID (prj\_\*) or slug
|
|
36
|
+
- `team?: string` - Team ID (team\_\*) or slug
|
|
37
|
+
- `expirationBufferMs?: number` - Buffer time in ms before expiry to trigger refresh (default: 0)
|
|
38
|
+
|
|
39
|
+
### `getVercelOidcTokenSync()`
|
|
40
|
+
|
|
41
|
+
Synchronously gets the current OIDC token without refreshing. Use `getVercelOidcToken()` if you need automatic refresh in development.
|
package/dist/auth-config.d.ts
CHANGED
|
@@ -27,4 +27,4 @@ export declare function writeAuthConfig(config: AuthConfig): void;
|
|
|
27
27
|
* Check if an access token is valid (not expired)
|
|
28
28
|
* Copied from packages/cli/src/util/client.ts:72-81
|
|
29
29
|
*/
|
|
30
|
-
export declare function isValidAccessToken(authConfig: AuthConfig): boolean;
|
|
30
|
+
export declare function isValidAccessToken(authConfig: AuthConfig, expirationBufferMs?: number): boolean;
|
package/dist/auth-config.js
CHANGED
|
@@ -56,7 +56,7 @@ function readAuthConfig() {
|
|
|
56
56
|
return null;
|
|
57
57
|
}
|
|
58
58
|
return JSON.parse(content);
|
|
59
|
-
} catch (
|
|
59
|
+
} catch (_error) {
|
|
60
60
|
return null;
|
|
61
61
|
}
|
|
62
62
|
}
|
|
@@ -68,13 +68,14 @@ function writeAuthConfig(config) {
|
|
|
68
68
|
}
|
|
69
69
|
fs.writeFileSync(authPath, JSON.stringify(config, null, 2), { mode: 384 });
|
|
70
70
|
}
|
|
71
|
-
function isValidAccessToken(authConfig) {
|
|
71
|
+
function isValidAccessToken(authConfig, expirationBufferMs = 0) {
|
|
72
72
|
if (!authConfig.token)
|
|
73
73
|
return false;
|
|
74
74
|
if (typeof authConfig.expiresAt !== "number")
|
|
75
75
|
return true;
|
|
76
76
|
const nowInSeconds = Math.floor(Date.now() / 1e3);
|
|
77
|
-
|
|
77
|
+
const bufferInSeconds = expirationBufferMs / 1e3;
|
|
78
|
+
return authConfig.expiresAt >= nowInSeconds + bufferInSeconds;
|
|
78
79
|
}
|
|
79
80
|
// Annotate the CommonJS export names for ESM import in node:
|
|
80
81
|
0 && (module.exports = {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error thrown when no authentication configuration is found.
|
|
3
|
+
* This typically means the user needs to log in.
|
|
4
|
+
*/
|
|
5
|
+
export declare class AccessTokenMissingError extends Error {
|
|
6
|
+
name: string;
|
|
7
|
+
constructor();
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Error thrown when attempting to refresh the authentication token fails.
|
|
11
|
+
* This includes cases where no refresh token is available.
|
|
12
|
+
*/
|
|
13
|
+
export declare class RefreshAccessTokenFailedError extends Error {
|
|
14
|
+
name: string;
|
|
15
|
+
constructor(cause?: unknown);
|
|
16
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var auth_errors_exports = {};
|
|
20
|
+
__export(auth_errors_exports, {
|
|
21
|
+
AccessTokenMissingError: () => AccessTokenMissingError,
|
|
22
|
+
RefreshAccessTokenFailedError: () => RefreshAccessTokenFailedError
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(auth_errors_exports);
|
|
25
|
+
class AccessTokenMissingError extends Error {
|
|
26
|
+
constructor() {
|
|
27
|
+
super(
|
|
28
|
+
"No authentication found. Please log in with the Vercel CLI (vercel login)."
|
|
29
|
+
);
|
|
30
|
+
this.name = "AccessTokenMissingError";
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
class RefreshAccessTokenFailedError extends Error {
|
|
34
|
+
constructor(cause) {
|
|
35
|
+
super("Failed to refresh authentication token.", { cause });
|
|
36
|
+
this.name = "RefreshAccessTokenFailedError";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
40
|
+
0 && (module.exports = {
|
|
41
|
+
AccessTokenMissingError,
|
|
42
|
+
RefreshAccessTokenFailedError
|
|
43
|
+
});
|
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for getting the Vercel OIDC token.
|
|
3
|
+
*/
|
|
4
|
+
export interface GetVercelOidcTokenOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Optional team ID (team_*) or slug to use for token refresh.
|
|
7
|
+
* When provided, this team will be used instead of reading from `.vercel/project.json`.
|
|
8
|
+
*/
|
|
9
|
+
team?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Optional project ID (prj_*) or slug to use for token refresh.
|
|
12
|
+
* When provided, this project will be used instead of reading from `.vercel/project.json`.
|
|
13
|
+
*/
|
|
14
|
+
project?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Optional time buffer in milliseconds before token expiry to consider it expired.
|
|
17
|
+
* When provided, the token will be refreshed if it expires within this buffer time.
|
|
18
|
+
* @default 0
|
|
19
|
+
*/
|
|
20
|
+
expirationBufferMs?: number;
|
|
21
|
+
}
|
|
1
22
|
/**
|
|
2
23
|
* Gets the current OIDC token from the request context or the environment variable.
|
|
3
24
|
*
|
|
@@ -8,6 +29,7 @@
|
|
|
8
29
|
*
|
|
9
30
|
* Unlike the `getVercelOidcTokenSync` function, this function will refresh the token if it is expired in a development environment.
|
|
10
31
|
*
|
|
32
|
+
* @param {GetVercelOidcTokenOptions} [options] - Optional configuration for token retrieval.
|
|
11
33
|
* @returns {Promise<string>} A promise that resolves to the OIDC token.
|
|
12
34
|
* @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
|
|
13
35
|
* is expired in a development environment, will also throw an error if the token cannot be refreshed: no CLI credentials are available, CLI credentials are expired, no project configuration is available
|
|
@@ -23,8 +45,19 @@
|
|
|
23
45
|
* console.error('Error:', error.message);
|
|
24
46
|
* });
|
|
25
47
|
* ```
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
*
|
|
51
|
+
* ```js
|
|
52
|
+
* // Using the OIDC token with explicit team and project (supports IDs and slugs)
|
|
53
|
+
* getVercelOidcToken({ team: 'my-team', project: 'my-project' }).then((token) => {
|
|
54
|
+
* console.log('OIDC Token:', token);
|
|
55
|
+
* }).catch((error) => {
|
|
56
|
+
* console.error('Error:', error.message);
|
|
57
|
+
* });
|
|
58
|
+
* ```
|
|
26
59
|
*/
|
|
27
|
-
export declare function getVercelOidcToken(): Promise<string>;
|
|
60
|
+
export declare function getVercelOidcToken(options?: GetVercelOidcTokenOptions): Promise<string>;
|
|
28
61
|
/**
|
|
29
62
|
* Gets the current OIDC token from the request context or the environment variable.
|
|
30
63
|
*
|
|
@@ -34,7 +34,7 @@ __export(get_vercel_oidc_token_exports, {
|
|
|
34
34
|
module.exports = __toCommonJS(get_vercel_oidc_token_exports);
|
|
35
35
|
var import_get_context = require("./get-context");
|
|
36
36
|
var import_token_error = require("./token-error");
|
|
37
|
-
async function getVercelOidcToken() {
|
|
37
|
+
async function getVercelOidcToken(options) {
|
|
38
38
|
let token = "";
|
|
39
39
|
let err;
|
|
40
40
|
try {
|
|
@@ -47,8 +47,8 @@ async function getVercelOidcToken() {
|
|
|
47
47
|
await import("./token-util.js"),
|
|
48
48
|
await import("./token.js")
|
|
49
49
|
]);
|
|
50
|
-
if (!token || isExpired(getTokenPayload(token))) {
|
|
51
|
-
await refreshToken();
|
|
50
|
+
if (!token || isExpired(getTokenPayload(token), options?.expirationBufferMs)) {
|
|
51
|
+
await refreshToken(options);
|
|
52
52
|
token = getVercelOidcTokenSync();
|
|
53
53
|
}
|
|
54
54
|
} catch (error) {
|
|
@@ -38,8 +38,8 @@ import_vitest.vi.mock("./get-context", () => ({
|
|
|
38
38
|
let userDataDir;
|
|
39
39
|
let cliDataDir;
|
|
40
40
|
let tokenDataDir;
|
|
41
|
-
const projectId = "
|
|
42
|
-
const teamId = "
|
|
41
|
+
const projectId = "prj_test123";
|
|
42
|
+
const teamId = "team_test456";
|
|
43
43
|
(0, import_vitest.beforeEach)(() => {
|
|
44
44
|
import_vitest.vi.clearAllMocks();
|
|
45
45
|
import_vitest.vi.restoreAllMocks();
|
|
@@ -63,14 +63,14 @@ import_vitest.vi.mock("./get-context", () => ({
|
|
|
63
63
|
fs.rmSync(rootDir, { recursive: true, force: true });
|
|
64
64
|
}
|
|
65
65
|
});
|
|
66
|
-
(0, import_vitest.test)("should throw
|
|
66
|
+
(0, import_vitest.test)("should throw AccessTokenMissingError when CLI auth file is missing", async () => {
|
|
67
67
|
fs.writeFileSync(
|
|
68
68
|
path.join(rootDir, ".vercel", "project.json"),
|
|
69
69
|
JSON.stringify({ projectId, orgId: teamId })
|
|
70
70
|
);
|
|
71
71
|
process.env.VERCEL_OIDC_TOKEN = createExpiredToken();
|
|
72
72
|
await (0, import_vitest.expect)((0, import_get_vercel_oidc_token.getVercelOidcToken)()).rejects.toThrow(
|
|
73
|
-
/
|
|
73
|
+
/No authentication found/
|
|
74
74
|
);
|
|
75
75
|
});
|
|
76
76
|
(0, import_vitest.test)("should throw helpful error when project.json is missing", async () => {
|
|
@@ -216,6 +216,124 @@ import_vitest.vi.mock("./get-context", () => ({
|
|
|
216
216
|
const token = await (0, import_get_vercel_oidc_token.getVercelOidcToken)();
|
|
217
217
|
(0, import_vitest.expect)(token).toBe(newToken);
|
|
218
218
|
});
|
|
219
|
+
(0, import_vitest.test)("should use provided team and project for refresh instead of reading project.json", async () => {
|
|
220
|
+
const customProjectId = "prj_custom123";
|
|
221
|
+
const customTeamId = "team_custom456";
|
|
222
|
+
fs.writeFileSync(
|
|
223
|
+
path.join(cliDataDir, "auth.json"),
|
|
224
|
+
JSON.stringify({ token: "test-auth-token" })
|
|
225
|
+
);
|
|
226
|
+
const newToken = createValidToken("custom-token");
|
|
227
|
+
const getVercelOidcTokenSpy = import_vitest.vi.spyOn(tokenUtil, "getVercelOidcToken").mockResolvedValue({
|
|
228
|
+
token: newToken
|
|
229
|
+
});
|
|
230
|
+
import_vitest.vi.spyOn(tokenUtil, "getTokenPayload").mockReturnValueOnce({
|
|
231
|
+
sub: "test-sub",
|
|
232
|
+
name: "test-name",
|
|
233
|
+
exp: Date.now() / 1e3 - 1e3
|
|
234
|
+
}).mockReturnValue({
|
|
235
|
+
sub: "test-sub",
|
|
236
|
+
name: "test-name",
|
|
237
|
+
exp: Date.now() / 1e3 + 43200
|
|
238
|
+
});
|
|
239
|
+
process.env.VERCEL_OIDC_TOKEN = createExpiredToken();
|
|
240
|
+
const token = await (0, import_get_vercel_oidc_token.getVercelOidcToken)({
|
|
241
|
+
team: customTeamId,
|
|
242
|
+
project: customProjectId
|
|
243
|
+
});
|
|
244
|
+
(0, import_vitest.expect)(token).toBe(newToken);
|
|
245
|
+
(0, import_vitest.expect)(getVercelOidcTokenSpy).toHaveBeenCalledWith(
|
|
246
|
+
"test-auth-token",
|
|
247
|
+
customProjectId,
|
|
248
|
+
customTeamId
|
|
249
|
+
);
|
|
250
|
+
});
|
|
251
|
+
(0, import_vitest.test)("should use provided project and read team from project.json", async () => {
|
|
252
|
+
const customProjectId = "prj_custom234";
|
|
253
|
+
fs.writeFileSync(
|
|
254
|
+
path.join(cliDataDir, "auth.json"),
|
|
255
|
+
JSON.stringify({ token: "test-auth-token" })
|
|
256
|
+
);
|
|
257
|
+
fs.writeFileSync(
|
|
258
|
+
path.join(rootDir, ".vercel", "project.json"),
|
|
259
|
+
JSON.stringify({ projectId: "original-project-id", orgId: teamId })
|
|
260
|
+
);
|
|
261
|
+
const newToken = createValidToken("partial-custom-token");
|
|
262
|
+
const getVercelOidcTokenSpy = import_vitest.vi.spyOn(tokenUtil, "getVercelOidcToken").mockResolvedValue({
|
|
263
|
+
token: newToken
|
|
264
|
+
});
|
|
265
|
+
import_vitest.vi.spyOn(tokenUtil, "getTokenPayload").mockReturnValueOnce({
|
|
266
|
+
sub: "test-sub",
|
|
267
|
+
name: "test-name",
|
|
268
|
+
exp: Date.now() / 1e3 - 1e3
|
|
269
|
+
}).mockReturnValue({
|
|
270
|
+
sub: "test-sub",
|
|
271
|
+
name: "test-name",
|
|
272
|
+
exp: Date.now() / 1e3 + 43200
|
|
273
|
+
});
|
|
274
|
+
process.env.VERCEL_OIDC_TOKEN = createExpiredToken();
|
|
275
|
+
const token = await (0, import_get_vercel_oidc_token.getVercelOidcToken)({
|
|
276
|
+
project: customProjectId
|
|
277
|
+
});
|
|
278
|
+
(0, import_vitest.expect)(token).toBe(newToken);
|
|
279
|
+
(0, import_vitest.expect)(getVercelOidcTokenSpy).toHaveBeenCalledWith(
|
|
280
|
+
"test-auth-token",
|
|
281
|
+
customProjectId,
|
|
282
|
+
teamId
|
|
283
|
+
);
|
|
284
|
+
});
|
|
285
|
+
(0, import_vitest.test)("should use provided team and read project from project.json", async () => {
|
|
286
|
+
const customTeamId = "team_custom789";
|
|
287
|
+
fs.writeFileSync(
|
|
288
|
+
path.join(cliDataDir, "auth.json"),
|
|
289
|
+
JSON.stringify({ token: "test-auth-token" })
|
|
290
|
+
);
|
|
291
|
+
fs.writeFileSync(
|
|
292
|
+
path.join(rootDir, ".vercel", "project.json"),
|
|
293
|
+
JSON.stringify({ projectId, orgId: "original-team-id" })
|
|
294
|
+
);
|
|
295
|
+
const newToken = createValidToken("partial-custom-token-2");
|
|
296
|
+
const getVercelOidcTokenSpy = import_vitest.vi.spyOn(tokenUtil, "getVercelOidcToken").mockResolvedValue({
|
|
297
|
+
token: newToken
|
|
298
|
+
});
|
|
299
|
+
import_vitest.vi.spyOn(tokenUtil, "getTokenPayload").mockReturnValueOnce({
|
|
300
|
+
sub: "test-sub",
|
|
301
|
+
name: "test-name",
|
|
302
|
+
exp: Date.now() / 1e3 - 1e3
|
|
303
|
+
}).mockReturnValue({
|
|
304
|
+
sub: "test-sub",
|
|
305
|
+
name: "test-name",
|
|
306
|
+
exp: Date.now() / 1e3 + 43200
|
|
307
|
+
});
|
|
308
|
+
process.env.VERCEL_OIDC_TOKEN = createExpiredToken();
|
|
309
|
+
const token = await (0, import_get_vercel_oidc_token.getVercelOidcToken)({
|
|
310
|
+
team: customTeamId
|
|
311
|
+
});
|
|
312
|
+
(0, import_vitest.expect)(token).toBe(newToken);
|
|
313
|
+
(0, import_vitest.expect)(getVercelOidcTokenSpy).toHaveBeenCalledWith(
|
|
314
|
+
"test-auth-token",
|
|
315
|
+
projectId,
|
|
316
|
+
customTeamId
|
|
317
|
+
);
|
|
318
|
+
});
|
|
319
|
+
(0, import_vitest.test)("should not refresh when token is valid even with options provided", async () => {
|
|
320
|
+
const validToken = createValidToken();
|
|
321
|
+
process.env.VERCEL_OIDC_TOKEN = validToken;
|
|
322
|
+
const getVercelOidcTokenSpy = import_vitest.vi.spyOn(tokenUtil, "getVercelOidcToken").mockResolvedValue({
|
|
323
|
+
token: "should-not-be-called"
|
|
324
|
+
});
|
|
325
|
+
import_vitest.vi.spyOn(tokenUtil, "getTokenPayload").mockReturnValue({
|
|
326
|
+
sub: "test-sub",
|
|
327
|
+
name: "test-name",
|
|
328
|
+
exp: Date.now() / 1e3 + 43200
|
|
329
|
+
});
|
|
330
|
+
const token = await (0, import_get_vercel_oidc_token.getVercelOidcToken)({
|
|
331
|
+
team: "custom-team",
|
|
332
|
+
project: "custom-project"
|
|
333
|
+
});
|
|
334
|
+
(0, import_vitest.expect)(token).toBe(validToken);
|
|
335
|
+
(0, import_vitest.expect)(getVercelOidcTokenSpy).not.toHaveBeenCalled();
|
|
336
|
+
});
|
|
219
337
|
});
|
|
220
338
|
function createExpiredToken() {
|
|
221
339
|
const header = Buffer.from(
|
package/dist/index-browser.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export { getContext } from './get-context';
|
|
2
|
+
export { AccessTokenMissingError, RefreshAccessTokenFailedError, } from './auth-errors';
|
|
2
3
|
export declare function getVercelOidcToken(): Promise<string>;
|
|
3
4
|
export declare function getVercelOidcTokenSync(): string;
|
|
5
|
+
export declare function getVercelToken(): Promise<string>;
|
package/dist/index-browser.js
CHANGED
|
@@ -18,21 +18,31 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var index_browser_exports = {};
|
|
20
20
|
__export(index_browser_exports, {
|
|
21
|
+
AccessTokenMissingError: () => import_auth_errors.AccessTokenMissingError,
|
|
22
|
+
RefreshAccessTokenFailedError: () => import_auth_errors.RefreshAccessTokenFailedError,
|
|
21
23
|
getContext: () => import_get_context.getContext,
|
|
22
24
|
getVercelOidcToken: () => getVercelOidcToken,
|
|
23
|
-
getVercelOidcTokenSync: () => getVercelOidcTokenSync
|
|
25
|
+
getVercelOidcTokenSync: () => getVercelOidcTokenSync,
|
|
26
|
+
getVercelToken: () => getVercelToken
|
|
24
27
|
});
|
|
25
28
|
module.exports = __toCommonJS(index_browser_exports);
|
|
26
29
|
var import_get_context = require("./get-context");
|
|
30
|
+
var import_auth_errors = require("./auth-errors");
|
|
27
31
|
async function getVercelOidcToken() {
|
|
28
32
|
return "";
|
|
29
33
|
}
|
|
30
34
|
function getVercelOidcTokenSync() {
|
|
31
35
|
return "";
|
|
32
36
|
}
|
|
37
|
+
async function getVercelToken() {
|
|
38
|
+
throw new Error("getVercelToken is not supported in browser environments");
|
|
39
|
+
}
|
|
33
40
|
// Annotate the CommonJS export names for ESM import in node:
|
|
34
41
|
0 && (module.exports = {
|
|
42
|
+
AccessTokenMissingError,
|
|
43
|
+
RefreshAccessTokenFailedError,
|
|
35
44
|
getContext,
|
|
36
45
|
getVercelOidcToken,
|
|
37
|
-
getVercelOidcTokenSync
|
|
46
|
+
getVercelOidcTokenSync,
|
|
47
|
+
getVercelToken
|
|
38
48
|
});
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -18,16 +18,24 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var src_exports = {};
|
|
20
20
|
__export(src_exports, {
|
|
21
|
+
AccessTokenMissingError: () => import_auth_errors.AccessTokenMissingError,
|
|
22
|
+
RefreshAccessTokenFailedError: () => import_auth_errors.RefreshAccessTokenFailedError,
|
|
21
23
|
getContext: () => import_get_context.getContext,
|
|
22
24
|
getVercelOidcToken: () => import_get_vercel_oidc_token.getVercelOidcToken,
|
|
23
|
-
getVercelOidcTokenSync: () => import_get_vercel_oidc_token.getVercelOidcTokenSync
|
|
25
|
+
getVercelOidcTokenSync: () => import_get_vercel_oidc_token.getVercelOidcTokenSync,
|
|
26
|
+
getVercelToken: () => import_token_util.getVercelToken
|
|
24
27
|
});
|
|
25
28
|
module.exports = __toCommonJS(src_exports);
|
|
26
29
|
var import_get_vercel_oidc_token = require("./get-vercel-oidc-token");
|
|
27
30
|
var import_get_context = require("./get-context");
|
|
31
|
+
var import_auth_errors = require("./auth-errors");
|
|
32
|
+
var import_token_util = require("./token-util");
|
|
28
33
|
// Annotate the CommonJS export names for ESM import in node:
|
|
29
34
|
0 && (module.exports = {
|
|
35
|
+
AccessTokenMissingError,
|
|
36
|
+
RefreshAccessTokenFailedError,
|
|
30
37
|
getContext,
|
|
31
38
|
getVercelOidcToken,
|
|
32
|
-
getVercelOidcTokenSync
|
|
39
|
+
getVercelOidcTokenSync,
|
|
40
|
+
getVercelToken
|
|
33
41
|
});
|
package/dist/token-io.js
CHANGED
package/dist/token-util.d.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
export declare function getVercelDataDir(): string | null;
|
|
2
|
-
export
|
|
2
|
+
export interface GetVercelTokenOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Optional time buffer in milliseconds before token expiry to consider it expired.
|
|
5
|
+
* When provided, the token will be refreshed if it expires within this buffer time.
|
|
6
|
+
* @default 0
|
|
7
|
+
*/
|
|
8
|
+
expirationBufferMs?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare function getVercelToken(options?: GetVercelTokenOptions): Promise<string>;
|
|
3
11
|
interface VercelTokenResponse {
|
|
4
12
|
token: string;
|
|
5
13
|
}
|
|
@@ -17,5 +25,5 @@ interface TokenPayload {
|
|
|
17
25
|
exp: number;
|
|
18
26
|
}
|
|
19
27
|
export declare function getTokenPayload(token: string): TokenPayload;
|
|
20
|
-
export declare function isExpired(token: TokenPayload): boolean;
|
|
28
|
+
export declare function isExpired(token: TokenPayload, bufferMs?: number): boolean;
|
|
21
29
|
export {};
|
package/dist/token-util.js
CHANGED
|
@@ -31,9 +31,9 @@ __export(token_util_exports, {
|
|
|
31
31
|
assertVercelOidcTokenResponse: () => assertVercelOidcTokenResponse,
|
|
32
32
|
findProjectInfo: () => findProjectInfo,
|
|
33
33
|
getTokenPayload: () => getTokenPayload,
|
|
34
|
-
getVercelCliToken: () => getVercelCliToken,
|
|
35
34
|
getVercelDataDir: () => getVercelDataDir,
|
|
36
35
|
getVercelOidcToken: () => getVercelOidcToken,
|
|
36
|
+
getVercelToken: () => getVercelToken,
|
|
37
37
|
isExpired: () => isExpired,
|
|
38
38
|
loadToken: () => loadToken,
|
|
39
39
|
saveToken: () => saveToken
|
|
@@ -45,6 +45,7 @@ var import_token_error = require("./token-error");
|
|
|
45
45
|
var import_token_io = require("./token-io");
|
|
46
46
|
var import_auth_config = require("./auth-config");
|
|
47
47
|
var import_oauth = require("./oauth");
|
|
48
|
+
var import_auth_errors = require("./auth-errors");
|
|
48
49
|
function getVercelDataDir() {
|
|
49
50
|
const vercelFolder = "com.vercel.cli";
|
|
50
51
|
const dataDir = (0, import_token_io.getUserDataDir)();
|
|
@@ -53,17 +54,17 @@ function getVercelDataDir() {
|
|
|
53
54
|
}
|
|
54
55
|
return path.join(dataDir, vercelFolder);
|
|
55
56
|
}
|
|
56
|
-
async function
|
|
57
|
+
async function getVercelToken(options) {
|
|
57
58
|
const authConfig = (0, import_auth_config.readAuthConfig)();
|
|
58
|
-
if (!authConfig) {
|
|
59
|
-
|
|
59
|
+
if (!authConfig?.token) {
|
|
60
|
+
throw new import_auth_errors.AccessTokenMissingError();
|
|
60
61
|
}
|
|
61
|
-
if ((0, import_auth_config.isValidAccessToken)(authConfig)) {
|
|
62
|
-
return authConfig.token
|
|
62
|
+
if ((0, import_auth_config.isValidAccessToken)(authConfig, options?.expirationBufferMs)) {
|
|
63
|
+
return authConfig.token;
|
|
63
64
|
}
|
|
64
65
|
if (!authConfig.refreshToken) {
|
|
65
66
|
(0, import_auth_config.writeAuthConfig)({});
|
|
66
|
-
|
|
67
|
+
throw new import_auth_errors.RefreshAccessTokenFailedError("No refresh token available");
|
|
67
68
|
}
|
|
68
69
|
try {
|
|
69
70
|
const tokenResponse = await (0, import_oauth.refreshTokenRequest)({
|
|
@@ -72,7 +73,7 @@ async function getVercelCliToken() {
|
|
|
72
73
|
const [tokensError, tokens] = await (0, import_oauth.processTokenResponse)(tokenResponse);
|
|
73
74
|
if (tokensError || !tokens) {
|
|
74
75
|
(0, import_auth_config.writeAuthConfig)({});
|
|
75
|
-
|
|
76
|
+
throw new import_auth_errors.RefreshAccessTokenFailedError(tokensError);
|
|
76
77
|
}
|
|
77
78
|
const updatedConfig = {
|
|
78
79
|
token: tokens.access_token,
|
|
@@ -82,10 +83,13 @@ async function getVercelCliToken() {
|
|
|
82
83
|
updatedConfig.refreshToken = tokens.refresh_token;
|
|
83
84
|
}
|
|
84
85
|
(0, import_auth_config.writeAuthConfig)(updatedConfig);
|
|
85
|
-
return updatedConfig.token
|
|
86
|
+
return updatedConfig.token;
|
|
86
87
|
} catch (error) {
|
|
87
88
|
(0, import_auth_config.writeAuthConfig)({});
|
|
88
|
-
|
|
89
|
+
if (error instanceof import_auth_errors.AccessTokenMissingError || error instanceof import_auth_errors.RefreshAccessTokenFailedError) {
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
throw new import_auth_errors.RefreshAccessTokenFailedError(error);
|
|
89
93
|
}
|
|
90
94
|
}
|
|
91
95
|
async function getVercelOidcToken(authToken, projectId, teamId) {
|
|
@@ -181,17 +185,17 @@ function getTokenPayload(token) {
|
|
|
181
185
|
);
|
|
182
186
|
return JSON.parse(Buffer.from(padded, "base64").toString("utf8"));
|
|
183
187
|
}
|
|
184
|
-
function isExpired(token) {
|
|
185
|
-
return token.exp * 1e3 < Date.now();
|
|
188
|
+
function isExpired(token, bufferMs = 0) {
|
|
189
|
+
return token.exp * 1e3 < Date.now() + bufferMs;
|
|
186
190
|
}
|
|
187
191
|
// Annotate the CommonJS export names for ESM import in node:
|
|
188
192
|
0 && (module.exports = {
|
|
189
193
|
assertVercelOidcTokenResponse,
|
|
190
194
|
findProjectInfo,
|
|
191
195
|
getTokenPayload,
|
|
192
|
-
getVercelCliToken,
|
|
193
196
|
getVercelDataDir,
|
|
194
197
|
getVercelOidcToken,
|
|
198
|
+
getVercelToken,
|
|
195
199
|
isExpired,
|
|
196
200
|
loadToken,
|
|
197
201
|
saveToken
|