oauth-init 1.0.0 → 1.1.0
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/README.md +3 -0
- package/dist/index.js +181 -5
- package/package.json +4 -2
package/README.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -10221,6 +10221,159 @@ ${callbackUrl}`, "Save this URL");
|
|
|
10221
10221
|
}
|
|
10222
10222
|
}
|
|
10223
10223
|
|
|
10224
|
+
// src/lib/providers/vercel.ts
|
|
10225
|
+
init_dist2();
|
|
10226
|
+
function logStep5(message) {
|
|
10227
|
+
if (!globalConfig.quiet)
|
|
10228
|
+
R2.step(message);
|
|
10229
|
+
}
|
|
10230
|
+
function logInfo2(message) {
|
|
10231
|
+
if (!globalConfig.quiet)
|
|
10232
|
+
R2.info(message);
|
|
10233
|
+
}
|
|
10234
|
+
function logMessage5(message) {
|
|
10235
|
+
if (!globalConfig.quiet)
|
|
10236
|
+
R2.message(message);
|
|
10237
|
+
}
|
|
10238
|
+
async function checkVercelCLI() {
|
|
10239
|
+
const s = bt2();
|
|
10240
|
+
s.start("Checking Vercel CLI...");
|
|
10241
|
+
try {
|
|
10242
|
+
await execa("vercel", ["--version"]);
|
|
10243
|
+
} catch {
|
|
10244
|
+
s.stop("Vercel CLI not found.");
|
|
10245
|
+
R2.error(`Vercel CLI is required for Vercel OAuth setup.
|
|
10246
|
+
` + `Install it: npm i -g vercel
|
|
10247
|
+
` + "Then run: vercel login");
|
|
10248
|
+
return false;
|
|
10249
|
+
}
|
|
10250
|
+
s.stop("Vercel CLI found.");
|
|
10251
|
+
return true;
|
|
10252
|
+
}
|
|
10253
|
+
async function checkVercelAuth() {
|
|
10254
|
+
const authSpinner = bt2();
|
|
10255
|
+
authSpinner.start("Checking Vercel authentication...");
|
|
10256
|
+
try {
|
|
10257
|
+
const { stdout } = await execa("vercel", ["whoami"]);
|
|
10258
|
+
if (!stdout.trim()) {
|
|
10259
|
+
authSpinner.stop("Not authenticated.");
|
|
10260
|
+
return { authenticated: false };
|
|
10261
|
+
}
|
|
10262
|
+
authSpinner.stop(`Logged in as: ${stdout.trim()}`);
|
|
10263
|
+
return { authenticated: true, user: stdout.trim() };
|
|
10264
|
+
} catch {
|
|
10265
|
+
authSpinner.stop("Not authenticated.");
|
|
10266
|
+
return { authenticated: false };
|
|
10267
|
+
}
|
|
10268
|
+
}
|
|
10269
|
+
async function getVercelTeams() {
|
|
10270
|
+
const loadingSpinner = bt2();
|
|
10271
|
+
loadingSpinner.start("Fetching Vercel teams...");
|
|
10272
|
+
try {
|
|
10273
|
+
const { stdout, stderr } = await execa("vercel", ["teams", "ls", "--format", "json"]);
|
|
10274
|
+
const teamsJson = JSON.parse(stdout);
|
|
10275
|
+
const teams = teamsJson.teams.map((team) => ({
|
|
10276
|
+
name: team.name,
|
|
10277
|
+
slug: team.slug
|
|
10278
|
+
}));
|
|
10279
|
+
loadingSpinner.stop("Fetched teams.");
|
|
10280
|
+
return teams;
|
|
10281
|
+
} catch (stderr) {
|
|
10282
|
+
loadingSpinner.stop("No teams found or not a team member. " + stderr);
|
|
10283
|
+
return [];
|
|
10284
|
+
}
|
|
10285
|
+
}
|
|
10286
|
+
|
|
10287
|
+
class VercelAuthProvider {
|
|
10288
|
+
async run(_appName) {
|
|
10289
|
+
try {
|
|
10290
|
+
const isCLIInstalled = await checkVercelCLI();
|
|
10291
|
+
if (!isCLIInstalled) {
|
|
10292
|
+
R2.error("Please install Vercel CLI and authenticate before continuing.");
|
|
10293
|
+
process.exit(1);
|
|
10294
|
+
}
|
|
10295
|
+
const auth = await checkVercelAuth();
|
|
10296
|
+
if (!auth.authenticated) {
|
|
10297
|
+
R2.error("Please run: vercel login");
|
|
10298
|
+
process.exit(1);
|
|
10299
|
+
}
|
|
10300
|
+
const teams = await getVercelTeams();
|
|
10301
|
+
let selectedTeam;
|
|
10302
|
+
if (teams.length === 0) {
|
|
10303
|
+
R2.error("No teams found. Please ensure you have a Vercel team or personal account.");
|
|
10304
|
+
process.exit(1);
|
|
10305
|
+
} else if (teams.length === 1) {
|
|
10306
|
+
selectedTeam = teams[0];
|
|
10307
|
+
logInfo2(`Using team: ${selectedTeam.name}`);
|
|
10308
|
+
} else {
|
|
10309
|
+
const teamId = await Je({
|
|
10310
|
+
message: "Select your team",
|
|
10311
|
+
options: teams.map((team) => ({
|
|
10312
|
+
label: team.name,
|
|
10313
|
+
value: team.slug
|
|
10314
|
+
}))
|
|
10315
|
+
});
|
|
10316
|
+
selectedTeam = { name: teamId, slug: teamId };
|
|
10317
|
+
}
|
|
10318
|
+
const teamSlug = selectedTeam.slug;
|
|
10319
|
+
const appsUrl = teamSlug ? `https://vercel.com/${teamSlug}/~/settings/apps` : `https://vercel.com/settings/apps`;
|
|
10320
|
+
logStep5("Step 1: Create Vercel OAuth App");
|
|
10321
|
+
logMessage5("Create an App in your Vercel dashboard to get OAuth credentials.");
|
|
10322
|
+
Ve(`Required Authorization Callback URL:
|
|
10323
|
+
${_appName}`, "Save this URL");
|
|
10324
|
+
if (!globalConfig.noOpen) {
|
|
10325
|
+
const shouldOpen = globalConfig.skipPrompts ? true : await Re({
|
|
10326
|
+
message: "Open Vercel Apps settings page?",
|
|
10327
|
+
initialValue: true
|
|
10328
|
+
});
|
|
10329
|
+
if (Ct(shouldOpen))
|
|
10330
|
+
return Ne("Setup aborted.");
|
|
10331
|
+
if (shouldOpen)
|
|
10332
|
+
await open_default(appsUrl);
|
|
10333
|
+
}
|
|
10334
|
+
if (!globalConfig.skipPrompts) {
|
|
10335
|
+
Ve(`1. Go to ${appsUrl}
|
|
10336
|
+
2. Click 'Create' to create a new App
|
|
10337
|
+
3. Enter Name and Slug for your app
|
|
10338
|
+
4. Configure Authorization Callback URL (use the URL above)
|
|
10339
|
+
5. Choose client authentication method
|
|
10340
|
+
6. Click Save
|
|
10341
|
+
7. Go to authentication tab, scroll down and generate secret`, "Action Required");
|
|
10342
|
+
await Ze({
|
|
10343
|
+
message: "Press Enter once you've created the app and generated a client secret (or type 'skip' if done previously)"
|
|
10344
|
+
});
|
|
10345
|
+
}
|
|
10346
|
+
logStep5("Step 2: Enter Vercel OAuth Credentials");
|
|
10347
|
+
let clientId;
|
|
10348
|
+
let clientSecret;
|
|
10349
|
+
if (globalConfig.skipPrompts) {
|
|
10350
|
+
R2.error("Client ID and Secret required in non-interactive mode. Run without --skip-prompts");
|
|
10351
|
+
process.exit(1);
|
|
10352
|
+
}
|
|
10353
|
+
clientId = await Ze({
|
|
10354
|
+
message: "Paste your Vercel Client ID:",
|
|
10355
|
+
placeholder: "your_client_id",
|
|
10356
|
+
validate: (value) => value && value.length > 0 ? undefined : "Client ID is required"
|
|
10357
|
+
});
|
|
10358
|
+
if (Ct(clientId))
|
|
10359
|
+
return Ne("Setup aborted.");
|
|
10360
|
+
clientSecret = await He({
|
|
10361
|
+
message: "Paste your Vercel Client Secret:"
|
|
10362
|
+
});
|
|
10363
|
+
if (Ct(clientSecret))
|
|
10364
|
+
return Ne("Setup aborted.");
|
|
10365
|
+
logStep5("Step 3: Save credentials");
|
|
10366
|
+
const saveOption = await askSaveOption();
|
|
10367
|
+
if (Ct(saveOption))
|
|
10368
|
+
return Ne("Setup aborted.");
|
|
10369
|
+
await saveCredentials(clientId, clientSecret, "vercel", saveOption);
|
|
10370
|
+
} catch (err) {
|
|
10371
|
+
R2.error(`Setup Failed: ${err.message}`);
|
|
10372
|
+
process.exit(1);
|
|
10373
|
+
}
|
|
10374
|
+
}
|
|
10375
|
+
}
|
|
10376
|
+
|
|
10224
10377
|
// src/index.ts
|
|
10225
10378
|
var AUTH_LIBRARIES = [
|
|
10226
10379
|
{ name: "next-auth", callbackPattern: "/api/auth/callback/[provider]" },
|
|
@@ -10280,7 +10433,15 @@ GitLab OAuth Setup:
|
|
|
10280
10433
|
1. Requires GitLab.com or GitLab Self-Managed
|
|
10281
10434
|
2. Redirect URI: http://localhost:3000/api/auth/callback/gitlab
|
|
10282
10435
|
3. Need: Application ID and Client Secret from GitLab Applications
|
|
10283
|
-
4. Supports user-owned, group-owned, or instance-wide apps
|
|
10436
|
+
4. Supports user-owned, group-owned, or instance-wide apps`,
|
|
10437
|
+
vercel: `
|
|
10438
|
+
Vercel OAuth Setup:
|
|
10439
|
+
1. Uses Vercel CLI to list your teams and open the correct settings page
|
|
10440
|
+
2. Requires: npm i -g vercel and vercel login
|
|
10441
|
+
3. Configure Authorization Callback URL: http://localhost:3000/api/auth/callback/vercel
|
|
10442
|
+
4. Generate a Client Secret in your app settings
|
|
10443
|
+
5. Get the Client ID from your app settings
|
|
10444
|
+
6. For better-auth: https://www.better-auth.com/docs/plugins/oauth#vercel`
|
|
10284
10445
|
};
|
|
10285
10446
|
function showProviderHelp(provider) {
|
|
10286
10447
|
const help = PROVIDER_HELP[provider.toLowerCase()];
|
|
@@ -10356,6 +10517,19 @@ async function setupOAuthServices(oauthServices, customCallbackUrl) {
|
|
|
10356
10517
|
}
|
|
10357
10518
|
const gitlabProvider = new GitLabAuthProvider;
|
|
10358
10519
|
await gitlabProvider.run(gitlabOauthCallback);
|
|
10520
|
+
} else if (service === "vercel") {
|
|
10521
|
+
R2.step("Vercel OAuth Setup");
|
|
10522
|
+
const vercelOauthCallback = globalConfig.skipPrompts ? defaultCallback : await Ze({
|
|
10523
|
+
message: "Enter the Vercel OAuth callback URL:",
|
|
10524
|
+
placeholder: defaultCallback,
|
|
10525
|
+
defaultValue: defaultCallback
|
|
10526
|
+
});
|
|
10527
|
+
if (Ct(vercelOauthCallback)) {
|
|
10528
|
+
Ne("Setup aborted.");
|
|
10529
|
+
return;
|
|
10530
|
+
}
|
|
10531
|
+
const vercelProvider = new VercelAuthProvider;
|
|
10532
|
+
await vercelProvider.run(vercelOauthCallback);
|
|
10359
10533
|
}
|
|
10360
10534
|
}
|
|
10361
10535
|
Le("OAuth setup completed! Thank you for using oauth-init!");
|
|
@@ -10371,7 +10545,7 @@ async function main() {
|
|
|
10371
10545
|
callbackUrl: args.find((arg) => arg.startsWith("--callback-url="))?.split("=")[1] || args.find((arg) => arg.startsWith("-c="))?.split("=")[1]
|
|
10372
10546
|
};
|
|
10373
10547
|
const providerArg = args.find((arg) => !arg.startsWith("-"));
|
|
10374
|
-
if (providerArg && (providerArg === "google" || providerArg === "github" || providerArg === "discord" || providerArg === "gitlab")) {
|
|
10548
|
+
if (providerArg && (providerArg === "google" || providerArg === "github" || providerArg === "discord" || providerArg === "gitlab" || providerArg === "vercel")) {
|
|
10375
10549
|
showProviderHelp(providerArg);
|
|
10376
10550
|
}
|
|
10377
10551
|
if (flags.help) {
|
|
@@ -10383,7 +10557,7 @@ Options:
|
|
|
10383
10557
|
-q, --quiet Reduce output verbosity
|
|
10384
10558
|
-n, --no-open Don't open browser URLs automatically
|
|
10385
10559
|
-y, --skip-prompts Use default options (for CI/CD)
|
|
10386
|
-
-p, --provider= Specify providers (comma-separated): google,github,discord
|
|
10560
|
+
-p, --provider= Specify providers (comma-separated): google,github,discord,gitlab,vercel
|
|
10387
10561
|
-c, --callback-url= Base callback URL (default: http://localhost:3000)
|
|
10388
10562
|
|
|
10389
10563
|
Examples:
|
|
@@ -10398,7 +10572,7 @@ Examples:
|
|
|
10398
10572
|
process.exit(0);
|
|
10399
10573
|
}
|
|
10400
10574
|
if (flags.provider) {
|
|
10401
|
-
const validProviders = ["google", "github", "discord", "gitlab"];
|
|
10575
|
+
const validProviders = ["google", "github", "discord", "gitlab", "vercel"];
|
|
10402
10576
|
const providers = flags.provider.split(",").map((p) => p.trim().toLowerCase());
|
|
10403
10577
|
const invalid = providers.filter((p) => !validProviders.includes(p));
|
|
10404
10578
|
if (invalid.length > 0) {
|
|
@@ -10441,7 +10615,9 @@ Examples:
|
|
|
10441
10615
|
{ value: "google", label: "Google" },
|
|
10442
10616
|
{ value: "github", label: "Github" },
|
|
10443
10617
|
{ value: "discord", label: "Discord" },
|
|
10444
|
-
{ value: "gitlab", label: "GitLab" }
|
|
10618
|
+
{ value: "gitlab", label: "GitLab" },
|
|
10619
|
+
{ value: "vercel", label: "Vercel" },
|
|
10620
|
+
{ value: "microsoft", label: "Microsoft", disabled: true, hint: "Coming soon" }
|
|
10445
10621
|
]
|
|
10446
10622
|
});
|
|
10447
10623
|
if (Ct(oauthToSetup)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oauth-init",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "CLI for setting up OAuth providers for your project",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -27,7 +27,9 @@
|
|
|
27
27
|
"setup",
|
|
28
28
|
"interactive",
|
|
29
29
|
"bun",
|
|
30
|
-
"typescript"
|
|
30
|
+
"typescript",
|
|
31
|
+
"vercel",
|
|
32
|
+
"gitlab"
|
|
31
33
|
],
|
|
32
34
|
"dependencies": {
|
|
33
35
|
"@clack/prompts": "^1.0.1",
|