@vercel/cli-auth 0.0.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/LICENSE +202 -0
- package/README.md +3 -0
- package/credentials-store.d.ts +29 -0
- package/credentials-store.js +108 -0
- package/credentials-store.js.map +1 -0
- package/credentials-store.ts +79 -0
- package/oauth.d.ts +207 -0
- package/oauth.js +311 -0
- package/oauth.js.map +1 -0
- package/oauth.ts +353 -0
- package/package.json +48 -0
- package/sso.d.ts +24 -0
- package/sso.js +136 -0
- package/sso.js.map +1 -0
- package/sso.ts +135 -0
- package/user-agent.d.ts +13 -0
- package/user-agent.js +20 -0
- package/user-agent.js.map +1 -0
- package/user-agent.ts +16 -0
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vercel/cli-auth",
|
|
3
|
+
"description": "Used by Vercel's CLIs to handle authentication",
|
|
4
|
+
"version": "0.0.1",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/vercel/vercel.git",
|
|
11
|
+
"directory": "packages/cli-auth"
|
|
12
|
+
},
|
|
13
|
+
"private": false,
|
|
14
|
+
"files": [
|
|
15
|
+
"*.js",
|
|
16
|
+
"*.js.map",
|
|
17
|
+
"*.ts",
|
|
18
|
+
"!vitest.config.mts",
|
|
19
|
+
"!**/*.test.ts"
|
|
20
|
+
],
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"async-listen": "3.0.0",
|
|
23
|
+
"open": "8.4.0",
|
|
24
|
+
"xdg-app-paths": "5",
|
|
25
|
+
"zod": "4.1.11"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@types/node": "22",
|
|
29
|
+
"memfs": "4.14.0",
|
|
30
|
+
"typescript": "5.9.2",
|
|
31
|
+
"vite": "7.1.7",
|
|
32
|
+
"vitest": "2.1.4"
|
|
33
|
+
},
|
|
34
|
+
"ci-cd": {
|
|
35
|
+
"//": "https://www.notion.so/1d6e06b059c48017a7afe7e8698de336",
|
|
36
|
+
"test": {
|
|
37
|
+
"requiredDependencies": [
|
|
38
|
+
"@api/tests"
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "pnpm clear && tsc -b",
|
|
44
|
+
"clear": "rm -rf *.js *.d.ts *.js.map tsconfig.tsbuildinfo",
|
|
45
|
+
"test": "vitest",
|
|
46
|
+
"typecheck": "tsc --noEmit"
|
|
47
|
+
}
|
|
48
|
+
}
|
package/sso.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as z from 'zod/mini';
|
|
2
|
+
import type { OAuth } from './oauth';
|
|
3
|
+
import type { Credentials } from './credentials-store';
|
|
4
|
+
/**
|
|
5
|
+
* Re-authorize a team's SSO session by opening the browser and waiting for the user to complete
|
|
6
|
+
* the SSO flow. Use when the user's SSO session has expired or missing.
|
|
7
|
+
*
|
|
8
|
+
*/
|
|
9
|
+
export declare function reauthorizeTeam(params: {
|
|
10
|
+
/** The team's slug that requires re-authorization */
|
|
11
|
+
team: string;
|
|
12
|
+
/** The current access token that needs to be re-authorized */
|
|
13
|
+
token: Credentials['token'];
|
|
14
|
+
oauth: OAuth;
|
|
15
|
+
}): Promise<void>;
|
|
16
|
+
declare const SSOError: z.ZodMiniObject<{
|
|
17
|
+
code: z.ZodMiniString<string>;
|
|
18
|
+
message: z.ZodMiniString<string>;
|
|
19
|
+
scope: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
20
|
+
enforced: z.ZodMiniOptional<z.ZodMiniBoolean<boolean>>;
|
|
21
|
+
}, z.core.$strip>;
|
|
22
|
+
/** Parse an error-like object to determine if SSO re-authorization is required. */
|
|
23
|
+
export declare function parseSSOError(error: unknown): z.infer<typeof SSOError> | undefined;
|
|
24
|
+
export {};
|
package/sso.js
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.reauthorizeTeam = reauthorizeTeam;
|
|
40
|
+
exports.parseSSOError = parseSSOError;
|
|
41
|
+
const node_http_1 = __importDefault(require("node:http"));
|
|
42
|
+
const async_listen_1 = require("async-listen");
|
|
43
|
+
const open_1 = __importDefault(require("open"));
|
|
44
|
+
const z = __importStar(require("zod/mini"));
|
|
45
|
+
/**
|
|
46
|
+
* Re-authorize a team's SSO session by opening the browser and waiting for the user to complete
|
|
47
|
+
* the SSO flow. Use when the user's SSO session has expired or missing.
|
|
48
|
+
*
|
|
49
|
+
*/
|
|
50
|
+
async function reauthorizeTeam(params) {
|
|
51
|
+
const { team, token, oauth } = params;
|
|
52
|
+
if (!token) {
|
|
53
|
+
throw new TypeError('Token is missing, cannot initiate SSO re-authorization. Please log in again.');
|
|
54
|
+
}
|
|
55
|
+
const introspection = await oauth.introspectToken(token);
|
|
56
|
+
const { active, session_id, client_id } = introspection;
|
|
57
|
+
if (!active || !session_id || !client_id) {
|
|
58
|
+
throw new Error('Introspection failed. Token is either expired or otherwise invalid. Please log in again.');
|
|
59
|
+
}
|
|
60
|
+
const verificationToken = await waitForVerification({
|
|
61
|
+
team,
|
|
62
|
+
session_id,
|
|
63
|
+
client_id,
|
|
64
|
+
});
|
|
65
|
+
await fetch(`https://api.vercel.com/registration/verify?${new URLSearchParams({ token: verificationToken })}`);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Get a verification token by spawning a localhost HTTP server
|
|
69
|
+
* that gets redirected to as the OAuth callback URL.
|
|
70
|
+
*
|
|
71
|
+
* The token returned can be sent back to the Vercel API to complete
|
|
72
|
+
* the SSO re-authorization.
|
|
73
|
+
*/
|
|
74
|
+
async function waitForVerification(params) {
|
|
75
|
+
const { team, session_id, client_id } = params;
|
|
76
|
+
const server = node_http_1.default.createServer();
|
|
77
|
+
const { port } = await (0, async_listen_1.listen)(server, 0, '127.0.0.1');
|
|
78
|
+
const initSSOUrl = new URL(`/sso/${team}?${new URLSearchParams({
|
|
79
|
+
session_id,
|
|
80
|
+
client_id,
|
|
81
|
+
next: `http://localhost:${port}`,
|
|
82
|
+
})}`, `https://vercel.com`);
|
|
83
|
+
try {
|
|
84
|
+
const [query] = await Promise.all([
|
|
85
|
+
new Promise((resolve, reject) => {
|
|
86
|
+
server.once('request', (req, res) => {
|
|
87
|
+
// Close the HTTP connection to prevent `server.close()` from hanging
|
|
88
|
+
res.setHeader('connection', 'close');
|
|
89
|
+
const { searchParams } = new URL(req.url || '/', 'http://localhost');
|
|
90
|
+
resolve(searchParams);
|
|
91
|
+
// Redirect the user back to the Vercel login notification page
|
|
92
|
+
res.statusCode = 302;
|
|
93
|
+
res.setHeader('location', getNotificationUrl(searchParams)).end();
|
|
94
|
+
});
|
|
95
|
+
server.once('error', reject);
|
|
96
|
+
}),
|
|
97
|
+
(0, open_1.default)(initSSOUrl.href),
|
|
98
|
+
]);
|
|
99
|
+
const loginError = query.get('loginError');
|
|
100
|
+
if (loginError) {
|
|
101
|
+
const error = new Error('Login failed.');
|
|
102
|
+
error.cause = JSON.parse(loginError);
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
const token = query.get('token');
|
|
106
|
+
if (!token) {
|
|
107
|
+
throw new TypeError('Could not get verification token. Please contact support.');
|
|
108
|
+
}
|
|
109
|
+
return token;
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
server.close();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function getNotificationUrl(params) {
|
|
116
|
+
const loginState = params.has('loginError')
|
|
117
|
+
? 'failed'
|
|
118
|
+
: params.has('ssoEmail')
|
|
119
|
+
? 'incomplete'
|
|
120
|
+
: 'success';
|
|
121
|
+
return `https://vercel.com/notifications/cli-login-${loginState}?${params}`;
|
|
122
|
+
}
|
|
123
|
+
const SSOError = z.object({
|
|
124
|
+
code: z.string(),
|
|
125
|
+
message: z.string(),
|
|
126
|
+
scope: z.optional(z.string()),
|
|
127
|
+
enforced: z.optional(z.boolean()),
|
|
128
|
+
});
|
|
129
|
+
/** Parse an error-like object to determine if SSO re-authorization is required. */
|
|
130
|
+
function parseSSOError(error) {
|
|
131
|
+
const { data } = SSOError.safeParse(error);
|
|
132
|
+
if (!data?.enforced)
|
|
133
|
+
return;
|
|
134
|
+
return data;
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=sso.js.map
|
package/sso.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sso.js","sourceRoot":"","sources":["sso.ts"],"names":[],"mappings":"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"}
|
package/sso.ts
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import http from 'node:http';
|
|
2
|
+
import { listen } from 'async-listen';
|
|
3
|
+
import open from 'open';
|
|
4
|
+
import * as z from 'zod/mini';
|
|
5
|
+
import type { OAuth } from './oauth';
|
|
6
|
+
import type { Credentials } from './credentials-store';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Re-authorize a team's SSO session by opening the browser and waiting for the user to complete
|
|
10
|
+
* the SSO flow. Use when the user's SSO session has expired or missing.
|
|
11
|
+
*
|
|
12
|
+
*/
|
|
13
|
+
export async function reauthorizeTeam(params: {
|
|
14
|
+
/** The team's slug that requires re-authorization */
|
|
15
|
+
team: string;
|
|
16
|
+
/** The current access token that needs to be re-authorized */
|
|
17
|
+
token: Credentials['token'];
|
|
18
|
+
oauth: OAuth;
|
|
19
|
+
}): Promise<void> {
|
|
20
|
+
const { team, token, oauth } = params;
|
|
21
|
+
|
|
22
|
+
if (!token) {
|
|
23
|
+
throw new TypeError(
|
|
24
|
+
'Token is missing, cannot initiate SSO re-authorization. Please log in again.'
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const introspection = await oauth.introspectToken(token);
|
|
29
|
+
const { active, session_id, client_id } = introspection;
|
|
30
|
+
|
|
31
|
+
if (!active || !session_id || !client_id) {
|
|
32
|
+
throw new Error(
|
|
33
|
+
'Introspection failed. Token is either expired or otherwise invalid. Please log in again.'
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const verificationToken = await waitForVerification({
|
|
38
|
+
team,
|
|
39
|
+
session_id,
|
|
40
|
+
client_id,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
await fetch(
|
|
44
|
+
`https://api.vercel.com/registration/verify?${new URLSearchParams({ token: verificationToken })}`
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Get a verification token by spawning a localhost HTTP server
|
|
50
|
+
* that gets redirected to as the OAuth callback URL.
|
|
51
|
+
*
|
|
52
|
+
* The token returned can be sent back to the Vercel API to complete
|
|
53
|
+
* the SSO re-authorization.
|
|
54
|
+
*/
|
|
55
|
+
async function waitForVerification(params: {
|
|
56
|
+
team: string;
|
|
57
|
+
session_id: string;
|
|
58
|
+
client_id: string;
|
|
59
|
+
}): Promise<string> {
|
|
60
|
+
const { team, session_id, client_id } = params;
|
|
61
|
+
const server = http.createServer();
|
|
62
|
+
const { port } = await listen(server, 0, '127.0.0.1');
|
|
63
|
+
const initSSOUrl = new URL(
|
|
64
|
+
`/sso/${team}?${new URLSearchParams({
|
|
65
|
+
session_id,
|
|
66
|
+
client_id,
|
|
67
|
+
next: `http://localhost:${port}`,
|
|
68
|
+
})}`,
|
|
69
|
+
`https://vercel.com`
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
const [query] = await Promise.all([
|
|
74
|
+
new Promise<URLSearchParams>((resolve, reject) => {
|
|
75
|
+
server.once('request', (req, res) => {
|
|
76
|
+
// Close the HTTP connection to prevent `server.close()` from hanging
|
|
77
|
+
res.setHeader('connection', 'close');
|
|
78
|
+
|
|
79
|
+
const { searchParams } = new URL(req.url || '/', 'http://localhost');
|
|
80
|
+
resolve(searchParams);
|
|
81
|
+
|
|
82
|
+
// Redirect the user back to the Vercel login notification page
|
|
83
|
+
res.statusCode = 302;
|
|
84
|
+
res.setHeader('location', getNotificationUrl(searchParams)).end();
|
|
85
|
+
});
|
|
86
|
+
server.once('error', reject);
|
|
87
|
+
}),
|
|
88
|
+
open(initSSOUrl.href),
|
|
89
|
+
]);
|
|
90
|
+
|
|
91
|
+
const loginError = query.get('loginError');
|
|
92
|
+
if (loginError) {
|
|
93
|
+
const error = new Error('Login failed.');
|
|
94
|
+
error.cause = JSON.parse(loginError);
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const token = query.get('token');
|
|
99
|
+
if (!token) {
|
|
100
|
+
throw new TypeError(
|
|
101
|
+
'Could not get verification token. Please contact support.'
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return token;
|
|
106
|
+
} finally {
|
|
107
|
+
server.close();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function getNotificationUrl(params: URLSearchParams): string {
|
|
112
|
+
const loginState = params.has('loginError')
|
|
113
|
+
? 'failed'
|
|
114
|
+
: params.has('ssoEmail')
|
|
115
|
+
? 'incomplete'
|
|
116
|
+
: 'success';
|
|
117
|
+
|
|
118
|
+
return `https://vercel.com/notifications/cli-login-${loginState}?${params}`;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const SSOError = z.object({
|
|
122
|
+
code: z.string(),
|
|
123
|
+
message: z.string(),
|
|
124
|
+
scope: z.optional(z.string()),
|
|
125
|
+
enforced: z.optional(z.boolean()),
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
/** Parse an error-like object to determine if SSO re-authorization is required. */
|
|
129
|
+
export function parseSSOError(
|
|
130
|
+
error: unknown
|
|
131
|
+
): z.infer<typeof SSOError> | undefined {
|
|
132
|
+
const { data } = SSOError.safeParse(error);
|
|
133
|
+
if (!data?.enforced) return;
|
|
134
|
+
return data;
|
|
135
|
+
}
|
package/user-agent.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get the user agent string for the current environment.
|
|
3
|
+
*
|
|
4
|
+
* @exapmle
|
|
5
|
+
* ```
|
|
6
|
+
* getUserAgent({ name: 'my-cli', version: '1.0.0' });
|
|
7
|
+
* // 'hostname @ my-cli 1.0.0 node-v18.16.0 linux (x64)'
|
|
8
|
+
* ```
|
|
9
|
+
*/
|
|
10
|
+
export declare function getUserAgent(pkg: {
|
|
11
|
+
name: string;
|
|
12
|
+
version: string;
|
|
13
|
+
}): string;
|
package/user-agent.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getUserAgent = getUserAgent;
|
|
7
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
8
|
+
/**
|
|
9
|
+
* Get the user agent string for the current environment.
|
|
10
|
+
*
|
|
11
|
+
* @exapmle
|
|
12
|
+
* ```
|
|
13
|
+
* getUserAgent({ name: 'my-cli', version: '1.0.0' });
|
|
14
|
+
* // 'hostname @ my-cli 1.0.0 node-v18.16.0 linux (x64)'
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
function getUserAgent(pkg) {
|
|
18
|
+
return `${node_os_1.default.hostname()} @ ${pkg.name} ${pkg.version} node-${process.version} ${node_os_1.default.platform()} (${node_os_1.default.arch()})`;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=user-agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-agent.js","sourceRoot":"","sources":["user-agent.ts"],"names":[],"mappings":";;;;;AAWA,oCAIC;AAfD,sDAAyB;AAEzB;;;;;;;;GAQG;AACH,SAAgB,YAAY,CAAC,GAAsC;IACjE,OAAO,GAAG,iBAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,OAAO,SAClD,OAAO,CAAC,OACV,IAAI,iBAAE,CAAC,QAAQ,EAAE,KAAK,iBAAE,CAAC,IAAI,EAAE,GAAG,CAAC;AACrC,CAAC"}
|
package/user-agent.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Get the user agent string for the current environment.
|
|
5
|
+
*
|
|
6
|
+
* @exapmle
|
|
7
|
+
* ```
|
|
8
|
+
* getUserAgent({ name: 'my-cli', version: '1.0.0' });
|
|
9
|
+
* // 'hostname @ my-cli 1.0.0 node-v18.16.0 linux (x64)'
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
export function getUserAgent(pkg: { name: string; version: string }): string {
|
|
13
|
+
return `${os.hostname()} @ ${pkg.name} ${pkg.version} node-${
|
|
14
|
+
process.version
|
|
15
|
+
} ${os.platform()} (${os.arch()})`;
|
|
16
|
+
}
|