@vercel/oidc 2.0.0 → 2.0.2
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 +18 -0
- package/dist/get-vercel-oidc-token.d.ts +7 -1
- package/dist/get-vercel-oidc-token.js +35 -1
- package/dist/token-error.d.ts +5 -0
- package/dist/token-error.js +40 -0
- package/dist/token-io.d.ts +2 -0
- package/dist/token-io.js +78 -0
- package/dist/token-util.d.ts +21 -0
- package/dist/token-util.js +178 -0
- package/dist/token.d.ts +1 -0
- package/dist/token.js +53 -0
- package/dist/token.test.d.ts +1 -0
- package/dist/token.test.js +84 -0
- package/docs/README.md +9 -3
- package/package.json +5 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @vercel/oidc
|
|
2
2
|
|
|
3
|
+
## 2.0.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- fix "Cannot find module" error caused by dynamically importing files without their extensions ([#13815](https://github.com/vercel/vercel/pull/13815))
|
|
8
|
+
|
|
9
|
+
## 2.0.1
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Fix package versions for oidc-aws-credentials-provider, vercel/functions, and publish the next version of vercel/oidc ([#13765](https://github.com/vercel/vercel/pull/13765))
|
|
14
|
+
|
|
15
|
+
## 2.1.0
|
|
16
|
+
|
|
17
|
+
### Minor Changes
|
|
18
|
+
|
|
19
|
+
- Add refresh token ability to @vercel/oidc ([#13608](https://github.com/vercel/vercel/pull/13608))
|
|
20
|
+
|
|
3
21
|
## 2.0.0
|
|
4
22
|
|
|
5
23
|
### Major Changes
|
|
@@ -6,8 +6,12 @@
|
|
|
6
6
|
* This function is used to retrieve the OIDC token from the request context or the environment variable.
|
|
7
7
|
* It checks for the `x-vercel-oidc-token` header in the request context and falls back to the `VERCEL_OIDC_TOKEN` environment variable if the header is not present.
|
|
8
8
|
*
|
|
9
|
+
* Unlike the `getVercelOidcTokenSync` function, this function will refresh the token if it is expired in a development environment.
|
|
10
|
+
*
|
|
9
11
|
* @returns {Promise<string>} A promise that resolves to the OIDC token.
|
|
10
|
-
* @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.
|
|
12
|
+
* @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
|
+
* 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
|
|
14
|
+
* or the token refresh request fails.
|
|
11
15
|
*
|
|
12
16
|
* @example
|
|
13
17
|
*
|
|
@@ -29,6 +33,8 @@ export declare function getVercelOidcToken(): Promise<string>;
|
|
|
29
33
|
* This function is used to retrieve the OIDC token from the request context or the environment variable.
|
|
30
34
|
* It checks for the `x-vercel-oidc-token` header in the request context and falls back to the `VERCEL_OIDC_TOKEN` environment variable if the header is not present.
|
|
31
35
|
*
|
|
36
|
+
* This function will not refresh the token if it is expired. For refreshing the token, use the @{link getVercelOidcToken} function.
|
|
37
|
+
*
|
|
32
38
|
* @returns {string} The OIDC token.
|
|
33
39
|
* @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.
|
|
34
40
|
*
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
var get_vercel_oidc_token_exports = {};
|
|
20
30
|
__export(get_vercel_oidc_token_exports, {
|
|
@@ -23,8 +33,32 @@ __export(get_vercel_oidc_token_exports, {
|
|
|
23
33
|
});
|
|
24
34
|
module.exports = __toCommonJS(get_vercel_oidc_token_exports);
|
|
25
35
|
var import_get_context = require("./get-context");
|
|
36
|
+
var import_token_error = require("./token-error");
|
|
26
37
|
async function getVercelOidcToken() {
|
|
27
|
-
|
|
38
|
+
let token = "";
|
|
39
|
+
let err;
|
|
40
|
+
try {
|
|
41
|
+
token = getVercelOidcTokenSync();
|
|
42
|
+
} catch (error) {
|
|
43
|
+
err = error;
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
const [{ getTokenPayload, isExpired }, { refreshToken }] = await Promise.all([
|
|
47
|
+
await import("./token-util.js"),
|
|
48
|
+
await import("./token.js")
|
|
49
|
+
]);
|
|
50
|
+
if (!token || isExpired(getTokenPayload(token))) {
|
|
51
|
+
await refreshToken();
|
|
52
|
+
token = getVercelOidcTokenSync();
|
|
53
|
+
}
|
|
54
|
+
} catch (error) {
|
|
55
|
+
if (err?.message && error instanceof Error) {
|
|
56
|
+
error.message = `${err.message}
|
|
57
|
+
${error.message}`;
|
|
58
|
+
}
|
|
59
|
+
throw new import_token_error.VercelOidcTokenError(`Failed to refresh OIDC token`, error);
|
|
60
|
+
}
|
|
61
|
+
return token;
|
|
28
62
|
}
|
|
29
63
|
function getVercelOidcTokenSync() {
|
|
30
64
|
const token = (0, import_get_context.getContext)().headers?.["x-vercel-oidc-token"] ?? process.env.VERCEL_OIDC_TOKEN;
|
|
@@ -0,0 +1,40 @@
|
|
|
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 token_error_exports = {};
|
|
20
|
+
__export(token_error_exports, {
|
|
21
|
+
VercelOidcTokenError: () => VercelOidcTokenError
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(token_error_exports);
|
|
24
|
+
class VercelOidcTokenError extends Error {
|
|
25
|
+
constructor(message, cause) {
|
|
26
|
+
super(message);
|
|
27
|
+
this.name = "VercelOidcTokenError";
|
|
28
|
+
this.cause = cause;
|
|
29
|
+
}
|
|
30
|
+
toString() {
|
|
31
|
+
if (this.cause) {
|
|
32
|
+
return `${this.name}: ${this.message}: ${this.cause}`;
|
|
33
|
+
}
|
|
34
|
+
return `${this.name}: ${this.message}`;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
38
|
+
0 && (module.exports = {
|
|
39
|
+
VercelOidcTokenError
|
|
40
|
+
});
|
package/dist/token-io.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var token_io_exports = {};
|
|
30
|
+
__export(token_io_exports, {
|
|
31
|
+
findRootDir: () => findRootDir,
|
|
32
|
+
getUserDataDir: () => getUserDataDir
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(token_io_exports);
|
|
35
|
+
var import_path = __toESM(require("path"));
|
|
36
|
+
var import_fs = __toESM(require("fs"));
|
|
37
|
+
var import_os = __toESM(require("os"));
|
|
38
|
+
var import_token_error = require("./token-error");
|
|
39
|
+
function findRootDir() {
|
|
40
|
+
try {
|
|
41
|
+
let dir = process.cwd();
|
|
42
|
+
while (dir !== import_path.default.dirname(dir)) {
|
|
43
|
+
const pkgPath = import_path.default.join(dir, ".vercel");
|
|
44
|
+
if (import_fs.default.existsSync(pkgPath)) {
|
|
45
|
+
return dir;
|
|
46
|
+
}
|
|
47
|
+
dir = import_path.default.dirname(dir);
|
|
48
|
+
}
|
|
49
|
+
} catch (e) {
|
|
50
|
+
throw new import_token_error.VercelOidcTokenError(
|
|
51
|
+
"Token refresh only supported in node server environments"
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
throw new import_token_error.VercelOidcTokenError("Unable to find root directory");
|
|
55
|
+
}
|
|
56
|
+
function getUserDataDir() {
|
|
57
|
+
if (process.env.XDG_DATA_HOME) {
|
|
58
|
+
return process.env.XDG_DATA_HOME;
|
|
59
|
+
}
|
|
60
|
+
switch (import_os.default.platform()) {
|
|
61
|
+
case "darwin":
|
|
62
|
+
return import_path.default.join(import_os.default.homedir(), "Library/Application Support");
|
|
63
|
+
case "linux":
|
|
64
|
+
return import_path.default.join(import_os.default.homedir(), ".local/share");
|
|
65
|
+
case "win32":
|
|
66
|
+
if (process.env.LOCALAPPDATA) {
|
|
67
|
+
return process.env.LOCALAPPDATA;
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
default:
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
75
|
+
0 && (module.exports = {
|
|
76
|
+
findRootDir,
|
|
77
|
+
getUserDataDir
|
|
78
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare function getVercelDataDir(): string | null;
|
|
2
|
+
export declare function getVercelCliToken(): string | null;
|
|
3
|
+
interface VercelTokenResponse {
|
|
4
|
+
token: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function getVercelOidcToken(authToken: string, projectId: string, teamId?: string): Promise<VercelTokenResponse | null>;
|
|
7
|
+
export declare function assertVercelOidcTokenResponse(res: unknown): asserts res is VercelTokenResponse;
|
|
8
|
+
export declare function findProjectInfo(): {
|
|
9
|
+
projectId: string;
|
|
10
|
+
teamId: string;
|
|
11
|
+
};
|
|
12
|
+
export declare function saveToken(token: VercelTokenResponse, projectId: string): void;
|
|
13
|
+
export declare function loadToken(projectId: string): VercelTokenResponse | null;
|
|
14
|
+
interface TokenPayload {
|
|
15
|
+
sub: string;
|
|
16
|
+
name: string;
|
|
17
|
+
exp: number;
|
|
18
|
+
}
|
|
19
|
+
export declare function getTokenPayload(token: string): TokenPayload;
|
|
20
|
+
export declare function isExpired(token: TokenPayload): boolean;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var token_util_exports = {};
|
|
30
|
+
__export(token_util_exports, {
|
|
31
|
+
assertVercelOidcTokenResponse: () => assertVercelOidcTokenResponse,
|
|
32
|
+
findProjectInfo: () => findProjectInfo,
|
|
33
|
+
getTokenPayload: () => getTokenPayload,
|
|
34
|
+
getVercelCliToken: () => getVercelCliToken,
|
|
35
|
+
getVercelDataDir: () => getVercelDataDir,
|
|
36
|
+
getVercelOidcToken: () => getVercelOidcToken,
|
|
37
|
+
isExpired: () => isExpired,
|
|
38
|
+
loadToken: () => loadToken,
|
|
39
|
+
saveToken: () => saveToken
|
|
40
|
+
});
|
|
41
|
+
module.exports = __toCommonJS(token_util_exports);
|
|
42
|
+
var path = __toESM(require("path"));
|
|
43
|
+
var fs = __toESM(require("fs"));
|
|
44
|
+
var import_token_error = require("./token-error");
|
|
45
|
+
var import_token_io = require("./token-io");
|
|
46
|
+
var import_ms = __toESM(require("ms"));
|
|
47
|
+
function getVercelDataDir() {
|
|
48
|
+
const vercelFolder = "com.vercel.cli";
|
|
49
|
+
const dataDir = (0, import_token_io.getUserDataDir)();
|
|
50
|
+
if (!dataDir) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
return path.join(dataDir, vercelFolder);
|
|
54
|
+
}
|
|
55
|
+
function getVercelCliToken() {
|
|
56
|
+
const dataDir = getVercelDataDir();
|
|
57
|
+
if (!dataDir) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
const tokenPath = path.join(dataDir, "auth.json");
|
|
61
|
+
if (!fs.existsSync(tokenPath)) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
const token = fs.readFileSync(tokenPath, "utf8");
|
|
65
|
+
if (!token) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
return JSON.parse(token).token;
|
|
69
|
+
}
|
|
70
|
+
async function getVercelOidcToken(authToken, projectId, teamId) {
|
|
71
|
+
try {
|
|
72
|
+
const url = `https://api.vercel.com/v1/projects/${projectId}/token?source=vercel-oidc-refresh${teamId ? `&teamId=${teamId}` : ""}`;
|
|
73
|
+
const res = await fetch(url, {
|
|
74
|
+
method: "POST",
|
|
75
|
+
headers: {
|
|
76
|
+
Authorization: `Bearer ${authToken}`
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
if (!res.ok) {
|
|
80
|
+
throw new import_token_error.VercelOidcTokenError(
|
|
81
|
+
`Failed to refresh OIDC token: ${res.statusText}`
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
const tokenRes = await res.json();
|
|
85
|
+
assertVercelOidcTokenResponse(tokenRes);
|
|
86
|
+
return tokenRes;
|
|
87
|
+
} catch (e) {
|
|
88
|
+
throw new import_token_error.VercelOidcTokenError(`Failed to refresh OIDC token`, e);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function assertVercelOidcTokenResponse(res) {
|
|
92
|
+
if (!res || typeof res !== "object") {
|
|
93
|
+
throw new TypeError("Expected an object");
|
|
94
|
+
}
|
|
95
|
+
if (!("token" in res) || typeof res.token !== "string") {
|
|
96
|
+
throw new TypeError("Expected a string-valued token property");
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function findProjectInfo() {
|
|
100
|
+
const dir = (0, import_token_io.findRootDir)();
|
|
101
|
+
if (!dir) {
|
|
102
|
+
throw new import_token_error.VercelOidcTokenError("Unable to find root directory");
|
|
103
|
+
}
|
|
104
|
+
try {
|
|
105
|
+
const prjPath = path.join(dir, ".vercel", "project.json");
|
|
106
|
+
if (!fs.existsSync(prjPath)) {
|
|
107
|
+
throw new import_token_error.VercelOidcTokenError("project.json not found");
|
|
108
|
+
}
|
|
109
|
+
const prj = JSON.parse(fs.readFileSync(prjPath, "utf8"));
|
|
110
|
+
if (typeof prj.projectId !== "string" && typeof prj.orgId !== "string") {
|
|
111
|
+
throw new TypeError("Expected a string-valued projectId property");
|
|
112
|
+
}
|
|
113
|
+
return { projectId: prj.projectId, teamId: prj.orgId };
|
|
114
|
+
} catch (e) {
|
|
115
|
+
throw new import_token_error.VercelOidcTokenError(`Unable to find project ID`, e);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function saveToken(token, projectId) {
|
|
119
|
+
try {
|
|
120
|
+
const dir = (0, import_token_io.getUserDataDir)();
|
|
121
|
+
if (!dir) {
|
|
122
|
+
throw new import_token_error.VercelOidcTokenError("Unable to find user data directory");
|
|
123
|
+
}
|
|
124
|
+
const tokenPath = path.join(dir, "com.vercel.token", `${projectId}.json`);
|
|
125
|
+
const tokenJson = JSON.stringify(token);
|
|
126
|
+
fs.mkdirSync(path.dirname(tokenPath), { mode: 432, recursive: true });
|
|
127
|
+
fs.writeFileSync(tokenPath, tokenJson);
|
|
128
|
+
fs.chmodSync(tokenPath, 432);
|
|
129
|
+
return;
|
|
130
|
+
} catch (e) {
|
|
131
|
+
throw new import_token_error.VercelOidcTokenError(`Failed to save token`, e);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
function loadToken(projectId) {
|
|
135
|
+
try {
|
|
136
|
+
const dir = (0, import_token_io.getUserDataDir)();
|
|
137
|
+
if (!dir) {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
const tokenPath = path.join(dir, "com.vercel.token", `${projectId}.json`);
|
|
141
|
+
if (!fs.existsSync(tokenPath)) {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
const token = JSON.parse(fs.readFileSync(tokenPath, "utf8"));
|
|
145
|
+
assertVercelOidcTokenResponse(token);
|
|
146
|
+
return token;
|
|
147
|
+
} catch (e) {
|
|
148
|
+
throw new import_token_error.VercelOidcTokenError(`Failed to load token`, e);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
function getTokenPayload(token) {
|
|
152
|
+
const tokenParts = token.split(".");
|
|
153
|
+
if (tokenParts.length !== 3) {
|
|
154
|
+
throw new import_token_error.VercelOidcTokenError("Invalid token");
|
|
155
|
+
}
|
|
156
|
+
const base64 = tokenParts[1].replace(/-/g, "+").replace(/_/g, "/");
|
|
157
|
+
const padded = base64.padEnd(
|
|
158
|
+
base64.length + (4 - base64.length % 4) % 4,
|
|
159
|
+
"="
|
|
160
|
+
);
|
|
161
|
+
return JSON.parse(Buffer.from(padded, "base64").toString("utf8"));
|
|
162
|
+
}
|
|
163
|
+
function isExpired(token) {
|
|
164
|
+
const timeout = (0, import_ms.default)("15m");
|
|
165
|
+
return token.exp * 1e3 < Date.now() + timeout;
|
|
166
|
+
}
|
|
167
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
168
|
+
0 && (module.exports = {
|
|
169
|
+
assertVercelOidcTokenResponse,
|
|
170
|
+
findProjectInfo,
|
|
171
|
+
getTokenPayload,
|
|
172
|
+
getVercelCliToken,
|
|
173
|
+
getVercelDataDir,
|
|
174
|
+
getVercelOidcToken,
|
|
175
|
+
isExpired,
|
|
176
|
+
loadToken,
|
|
177
|
+
saveToken
|
|
178
|
+
});
|
package/dist/token.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function refreshToken(): Promise<void>;
|
package/dist/token.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
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 token_exports = {};
|
|
20
|
+
__export(token_exports, {
|
|
21
|
+
refreshToken: () => refreshToken
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(token_exports);
|
|
24
|
+
var import_token_error = require("./token-error");
|
|
25
|
+
var import_token_util = require("./token-util");
|
|
26
|
+
async function refreshToken() {
|
|
27
|
+
const { projectId, teamId } = (0, import_token_util.findProjectInfo)();
|
|
28
|
+
let maybeToken = (0, import_token_util.loadToken)(projectId);
|
|
29
|
+
if (!maybeToken || (0, import_token_util.isExpired)((0, import_token_util.getTokenPayload)(maybeToken.token))) {
|
|
30
|
+
const authToken = (0, import_token_util.getVercelCliToken)();
|
|
31
|
+
if (!authToken) {
|
|
32
|
+
throw new import_token_error.VercelOidcTokenError(
|
|
33
|
+
"Failed to refresh OIDC token: login to vercel cli"
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
if (!projectId) {
|
|
37
|
+
throw new import_token_error.VercelOidcTokenError(
|
|
38
|
+
"Failed to refresh OIDC token: project id not found"
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
maybeToken = await (0, import_token_util.getVercelOidcToken)(authToken, projectId, teamId);
|
|
42
|
+
if (!maybeToken) {
|
|
43
|
+
throw new import_token_error.VercelOidcTokenError("Failed to refresh OIDC token");
|
|
44
|
+
}
|
|
45
|
+
(0, import_token_util.saveToken)(maybeToken, projectId);
|
|
46
|
+
}
|
|
47
|
+
process.env.VERCEL_OIDC_TOKEN = maybeToken.token;
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
51
|
+
0 && (module.exports = {
|
|
52
|
+
refreshToken
|
|
53
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (let key of __getOwnPropNames(from))
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
12
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
13
|
+
}
|
|
14
|
+
return to;
|
|
15
|
+
};
|
|
16
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
17
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
18
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
19
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
20
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
|
+
mod
|
|
23
|
+
));
|
|
24
|
+
var import_crypto = require("crypto");
|
|
25
|
+
var import_vitest = require("vitest");
|
|
26
|
+
var os = __toESM(require("os"));
|
|
27
|
+
var path = __toESM(require("path"));
|
|
28
|
+
var fs = __toESM(require("fs"));
|
|
29
|
+
var import_token_io = require("./token-io");
|
|
30
|
+
var tokenUtil = __toESM(require("./token-util"));
|
|
31
|
+
var import_token = require("./token");
|
|
32
|
+
import_vitest.vi.mock("./token-io");
|
|
33
|
+
(0, import_vitest.describe)("refreshToken", () => {
|
|
34
|
+
let rootDir;
|
|
35
|
+
let userDataDir;
|
|
36
|
+
let cliDataDir;
|
|
37
|
+
let tokenDataDir;
|
|
38
|
+
const projectId = "test-project-id";
|
|
39
|
+
(0, import_vitest.beforeEach)(() => {
|
|
40
|
+
import_vitest.vi.clearAllMocks();
|
|
41
|
+
process.env.VERCEL_OIDC_TOKEN = void 0;
|
|
42
|
+
const random = `test-${(0, import_crypto.randomUUID)()}`;
|
|
43
|
+
rootDir = path.join(os.tmpdir(), random);
|
|
44
|
+
userDataDir = path.join(rootDir, "data");
|
|
45
|
+
cliDataDir = path.join(userDataDir, "com.vercel.cli");
|
|
46
|
+
tokenDataDir = path.join(userDataDir, "com.vercel.token");
|
|
47
|
+
fs.mkdirSync(cliDataDir, { recursive: true });
|
|
48
|
+
fs.mkdirSync(tokenDataDir, { recursive: true });
|
|
49
|
+
fs.mkdirSync(path.join(rootDir, ".vercel"), {
|
|
50
|
+
recursive: true
|
|
51
|
+
});
|
|
52
|
+
fs.writeFileSync(path.join(cliDataDir, "auth.json"), '{token: "test"}');
|
|
53
|
+
fs.writeFileSync(
|
|
54
|
+
path.join(rootDir, ".vercel", "project.json"),
|
|
55
|
+
JSON.stringify({ projectId })
|
|
56
|
+
);
|
|
57
|
+
import_vitest.vi.spyOn(process, "cwd").mockReturnValue(rootDir);
|
|
58
|
+
import_vitest.vi.mocked(import_token_io.findRootDir).mockReturnValue(rootDir);
|
|
59
|
+
import_vitest.vi.mocked(import_token_io.getUserDataDir).mockReturnValue(userDataDir);
|
|
60
|
+
import_vitest.vi.spyOn(tokenUtil, "getVercelCliToken").mockReturnValue("test");
|
|
61
|
+
import_vitest.vi.spyOn(tokenUtil, "getVercelOidcToken").mockResolvedValue({
|
|
62
|
+
token: "test-token"
|
|
63
|
+
});
|
|
64
|
+
import_vitest.vi.spyOn(tokenUtil, "getTokenPayload").mockReturnValue({
|
|
65
|
+
sub: "test-sub",
|
|
66
|
+
name: "test-name",
|
|
67
|
+
exp: Date.now() + 1e5
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
(0, import_vitest.test)("should correctly load saved token from file", async () => {
|
|
71
|
+
const token = { token: "test-saved" };
|
|
72
|
+
const tokenPath = path.join(tokenDataDir, `${projectId}.json`);
|
|
73
|
+
fs.writeFileSync(tokenPath, JSON.stringify(token));
|
|
74
|
+
await (0, import_token.refreshToken)();
|
|
75
|
+
(0, import_vitest.expect)(process.env.VERCEL_OIDC_TOKEN).toBe("test-saved");
|
|
76
|
+
});
|
|
77
|
+
(0, import_vitest.test)("should correctly save token to file", async () => {
|
|
78
|
+
await (0, import_token.refreshToken)();
|
|
79
|
+
(0, import_vitest.expect)(process.env.VERCEL_OIDC_TOKEN).toBe("test-token");
|
|
80
|
+
const tokenPath = path.join(tokenDataDir, `${projectId}.json`);
|
|
81
|
+
const token = JSON.parse(fs.readFileSync(tokenPath, "utf8"));
|
|
82
|
+
(0, import_vitest.expect)(token).toEqual({ token: "test-token" });
|
|
83
|
+
});
|
|
84
|
+
});
|
package/docs/README.md
CHANGED
|
@@ -20,9 +20,13 @@ Do not cache this value, as it is subject to change in production!
|
|
|
20
20
|
This function is used to retrieve the OIDC token from the request context or the environment variable.
|
|
21
21
|
It checks for the `x-vercel-oidc-token` header in the request context and falls back to the `VERCEL_OIDC_TOKEN` environment variable if the header is not present.
|
|
22
22
|
|
|
23
|
+
Unlike the `getVercelOidcTokenSync` function, this function will refresh the token if it is expired in a development environment.
|
|
24
|
+
|
|
23
25
|
**`Throws`**
|
|
24
26
|
|
|
25
|
-
If the `x-vercel-oidc-token` header is missing from the request context and the environment variable `VERCEL_OIDC_TOKEN` is not set.
|
|
27
|
+
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
|
|
28
|
+
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
|
|
29
|
+
or the token refresh request fails.
|
|
26
30
|
|
|
27
31
|
**`Example`**
|
|
28
32
|
|
|
@@ -45,7 +49,7 @@ A promise that resolves to the OIDC token.
|
|
|
45
49
|
|
|
46
50
|
#### Defined in
|
|
47
51
|
|
|
48
|
-
[get-vercel-oidc-token.ts:
|
|
52
|
+
[get-vercel-oidc-token.ts:30](https://github.com/vercel/vercel/blob/main/packages/oidc/src/get-vercel-oidc-token.ts#L30)
|
|
49
53
|
|
|
50
54
|
---
|
|
51
55
|
|
|
@@ -60,6 +64,8 @@ Do not cache this value, as it is subject to change in production!
|
|
|
60
64
|
This function is used to retrieve the OIDC token from the request context or the environment variable.
|
|
61
65
|
It checks for the `x-vercel-oidc-token` header in the request context and falls back to the `VERCEL_OIDC_TOKEN` environment variable if the header is not present.
|
|
62
66
|
|
|
67
|
+
This function will not refresh the token if it is expired. For refreshing the token, use the @{link getVercelOidcToken} function.
|
|
68
|
+
|
|
63
69
|
**`Throws`**
|
|
64
70
|
|
|
65
71
|
If the `x-vercel-oidc-token` header is missing from the request context and the environment variable `VERCEL_OIDC_TOKEN` is not set.
|
|
@@ -80,4 +86,4 @@ The OIDC token.
|
|
|
80
86
|
|
|
81
87
|
#### Defined in
|
|
82
88
|
|
|
83
|
-
[get-vercel-oidc-token.ts:
|
|
89
|
+
[get-vercel-oidc-token.ts:81](https://github.com/vercel/vercel/blob/main/packages/oidc/src/get-vercel-oidc-token.ts#L81)
|
package/package.json
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"require": "./dist/index.js"
|
|
15
15
|
}
|
|
16
16
|
},
|
|
17
|
-
"version": "2.0.
|
|
17
|
+
"version": "2.0.2",
|
|
18
18
|
"repository": {
|
|
19
19
|
"directory": "packages/oidc",
|
|
20
20
|
"type": "git",
|
|
@@ -39,6 +39,10 @@
|
|
|
39
39
|
"publishConfig": {
|
|
40
40
|
"access": "public"
|
|
41
41
|
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@types/ms": "2.1.0",
|
|
44
|
+
"ms": "2.1.3"
|
|
45
|
+
},
|
|
42
46
|
"scripts": {
|
|
43
47
|
"pretest": "pnpm run build:code",
|
|
44
48
|
"test": "vitest",
|