Add authentication and application management scripts for Azure AD

This commit is contained in:
2026-01-26 22:31:27 +01:00
parent bf9a85199e
commit 5b5ab6b78b
6 changed files with 636 additions and 12 deletions

163
bin/setup-app.cjs Executable file
View File

@@ -0,0 +1,163 @@
#!/usr/bin/env node
const { execSync, spawnSync } = require("child_process");
const { writeFileSync } = require("fs");
const { parseArgs } = require("util");
const args = parseArgs({
options: {
"app-name": { type: "string", short: "a" },
help: { type: "boolean", short: "h" },
"generate-client-secret": { type: "boolean", short: "s" },
},
});
const config = {};
if (args.values["app-name"]) {
config.appName = args.values["app-name"];
} else {
config.appName = "Azure Node Playground";
}
// Get the tenant ID
try {
config.tenantId = execSync(`az account show --query "tenantId" -o tsv`)
.toString()
.trim();
} catch (error) {
console.error("Failed to get Azure tenant ID.");
process.exit(1);
}
if (config.tenantId) {
console.log(`Using Tenant ID: ${config.tenantId}`);
} else {
console.error("Failed to get Azure tenant ID.");
process.exit(1);
}
try {
const appIdList = JSON.parse(
execSync(
`az ad app list --filter "displayName eq '${config.appName}'" -o json`,
)
.toString()
.trim(),
);
if (appIdList.length !== 1) {
throw new Error("App not found or multiple apps with the same name.");
}
config.appId = appIdList[0].appId;
} catch (error) {
console.error("Failed to query Azure AD applications.");
process.exit(1);
}
if (config.appId) {
console.log(`App already exists with ID: ${config.appId}`);
} else {
// Create the Azure AD application, capturing the JSON output, and extracting the .appId
try {
config.appId = execSync(
`az ad app create --display-name "${config.appName}" --query "appId" -o tsv`,
)
.toString()
.trim();
} catch (error) {
console.error("Failed to create Azure AD application.");
process.exit(1);
}
console.log(`Created App with ID: ${config.appId}`);
}
// Chech if service principal exists
let spObjId;
try {
const spIdList = JSON.parse(
execSync(`az ad sp list --filter "appId eq '${config.appId}'" -o json`)
.toString()
.trim(),
);
if (spIdList.length === 1) {
spObjId = spIdList[0].id;
} else {
spObjId = null;
}
} catch (error) {
console.error("Failed to query service principals.");
process.exit(1);
}
if (spObjId) {
console.log("Using existing service principal.");
} else {
// Now create the service principal for the app
try {
spObjId = execSync(
`az ad sp create --id ${config.appId} --query "id" -o tsv`,
);
console.log("Service principal created.");
} catch (error) {
console.log("Failed to create service principal.");
}
}
if (args.values["generate-client-secret"]) {
// Generate a new client secret for the application
try {
result = spawnSync(
"az",
[
"ad",
"app",
"credential",
"reset",
"--id",
config.appId,
"--query",
"password",
"-o",
"tsv",
],
{ encoding: "utf-8" },
);
config.clientSecret = result.stdout.toString().trim();
console.log("Client secret generated.");
} catch (error) {
console.error("Failed to generate client secret.");
console.error(error);
process.exit(1);
}
}
// Write the APP_ID to the .env file
const envContent = `AZ_APP_NAME="${config.appName}"
ARM_TENANT_ID=${config.tenantId}
ARM_CLIENT_ID=${config.appId}
ARM_CLIENT_SECRET=${config.clientSecret || ""}
`;
writeFileSync(".env", envContent);
console.log(".env file created with application configuration.");
// Save the config to the 'config.js' file.
writeFileSync(
"config.js",
`export const config = ${JSON.stringify(config, null, 4)};\n`,
);
console.log("config.js file created.");
// Check if we can change file mode permissions (Unix-like systems)
// for sensitive files like .env and config.js.
try {
execSync("chmod 600 .env config.js");
console.log("File permissions for .env and config.js set to 600.");
} catch (error) {
console.warn(
"Could not set file permissions. Please ensure .env and config.js are secured appropriately.",
);
}
console.log("Setup complete.");