Refactor getCredential and loginInteractive functions for improved error handling and browser specification
This commit is contained in:
63
src/azure.js
63
src/azure.js
@@ -1,13 +1,20 @@
|
||||
// azure.js
|
||||
import http from "node:http";
|
||||
import { URL } from "node:url";
|
||||
import open from "open";
|
||||
import open, { apps } from "open";
|
||||
import crypto from "node:crypto";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import os from "node:os";
|
||||
import { PublicClientApplication, ConfidentialClientApplication } from "@azure/msal-node";
|
||||
import { DefaultAzureCredential, ClientSecretCredential, DeviceCodeCredential } from "@azure/identity";
|
||||
import {
|
||||
PublicClientApplication,
|
||||
ConfidentialClientApplication,
|
||||
} from "@azure/msal-node";
|
||||
import {
|
||||
DefaultAzureCredential,
|
||||
ClientSecretCredential,
|
||||
DeviceCodeCredential,
|
||||
} from "@azure/identity";
|
||||
|
||||
export async function getCredential(credentialType, options) {
|
||||
switch (credentialType) {
|
||||
@@ -17,17 +24,21 @@ export async function getCredential(credentialType, options) {
|
||||
case "cs":
|
||||
case "clientSecret":
|
||||
if (!options.tenantId || !options.clientId || !options.clientSecret) {
|
||||
throw new Error("tenantId, clientId, and clientSecret are required for ClientSecretCredential");
|
||||
throw new Error(
|
||||
"tenantId, clientId, and clientSecret are required for ClientSecretCredential",
|
||||
);
|
||||
}
|
||||
return new ClientSecretCredential(
|
||||
options.tenantId,
|
||||
options.clientId,
|
||||
options.clientSecret
|
||||
options.clientSecret,
|
||||
);
|
||||
case "dc":
|
||||
case "deviceCode":
|
||||
if (!options.tenantId || !options.clientId) {
|
||||
throw new Error("tenantId and clientId are required for DeviceCodeCredential");
|
||||
throw new Error(
|
||||
"tenantId and clientId are required for DeviceCodeCredential",
|
||||
);
|
||||
}
|
||||
return new DeviceCodeCredential({
|
||||
tenantId: options.tenantId,
|
||||
@@ -45,18 +56,13 @@ function fileCachePlugin(cachePath) {
|
||||
return {
|
||||
beforeCacheAccess: async (ctx) => {
|
||||
if (fs.existsSync(cachePath)) {
|
||||
ctx.tokenCache.deserialize(
|
||||
fs.readFileSync(cachePath, "utf8")
|
||||
);
|
||||
ctx.tokenCache.deserialize(fs.readFileSync(cachePath, "utf8"));
|
||||
}
|
||||
},
|
||||
afterCacheAccess: async (ctx) => {
|
||||
if (ctx.cacheHasChanged) {
|
||||
fs.mkdirSync(path.dirname(cachePath), { recursive: true });
|
||||
fs.writeFileSync(
|
||||
cachePath,
|
||||
ctx.tokenCache.serialize()
|
||||
);
|
||||
fs.writeFileSync(cachePath, ctx.tokenCache.serialize());
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -72,16 +78,22 @@ function generatePkce() {
|
||||
return { verifier, challenge, challengeMethod: "S256" };
|
||||
}
|
||||
|
||||
export async function loginInteractive({ tenantId, clientId, scopes }) {
|
||||
export async function loginInteractive({ appName, tenantId, clientId, scopes }) {
|
||||
if (!tenantId) throw new Error("tenantId is required");
|
||||
if (!clientId) throw new Error("clientId is required");
|
||||
if (!Array.isArray(scopes) || scopes.length === 0)
|
||||
throw new Error("scopes[] is required");
|
||||
|
||||
// Make app name lowercase with all non-alphanumeric characters removed
|
||||
// spaces replaced with dashes and all letters converted to lowercase
|
||||
const sanitizedAppName = (appName || "Azure Node Login")
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, "-");
|
||||
|
||||
const cachePath = path.join(
|
||||
os.homedir(),
|
||||
".config/azure-node-playground",
|
||||
`${clientId}-token-cache.json`
|
||||
`.config/${sanitizedAppName}`,
|
||||
`${clientId}-token-cache.json`,
|
||||
);
|
||||
|
||||
const pca = new PublicClientApplication({
|
||||
@@ -142,7 +154,9 @@ export async function loginInteractive({ tenantId, clientId, scopes }) {
|
||||
|
||||
resolve(token);
|
||||
} catch (e) {
|
||||
try { server.close(); } catch {}
|
||||
try {
|
||||
server.close();
|
||||
} catch {}
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
@@ -160,10 +174,19 @@ export async function loginInteractive({ tenantId, clientId, scopes }) {
|
||||
codeChallengeMethod: pkce.challengeMethod,
|
||||
});
|
||||
|
||||
try { await open(authUrl, { wait: false }); } catch {}
|
||||
console.log("If the browser didn't open, visit:\n" + authUrl);
|
||||
try {
|
||||
await open(authUrl, {
|
||||
wait: false,
|
||||
app: {
|
||||
name: apps.edge, // Enforce using Microsoft Edge browser
|
||||
},
|
||||
});
|
||||
} catch {}
|
||||
console.log("Visit:\n" + authUrl);
|
||||
} catch (e) {
|
||||
try { server.close(); } catch {}
|
||||
try {
|
||||
server.close();
|
||||
} catch {}
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user