Update: implement token caching in loginInteractive and enhance error handling
This commit is contained in:
@@ -1,12 +1,21 @@
|
|||||||
import { loginInteractive } from "../src/auth.js";
|
import { loginInteractive } from "../src/auth.js";
|
||||||
import { config } from "../public-config.js";
|
import { config } from "../public-config.js";
|
||||||
|
|
||||||
const scopes = ["https://management.azure.com/.default"];
|
const scopes = ["https://management.azure.com/.default"];
|
||||||
|
|
||||||
const token = await loginInteractive({
|
let token;
|
||||||
tenantId: config.tenantId,
|
|
||||||
clientId: config.clientId,
|
try {
|
||||||
scopes,
|
token = await loginInteractive({
|
||||||
});
|
tenantId: config.tenantId,
|
||||||
|
clientId: config.clientId,
|
||||||
|
scopes,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Login failed:", e);
|
||||||
|
console.error(e.stack);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
console.log("Access token acquired:");
|
console.log("Access token acquired:");
|
||||||
console.log(token.accessToken);
|
//console.log(token.accessToken);
|
||||||
|
|||||||
47
src/auth.js
47
src/auth.js
@@ -4,6 +4,30 @@ import { URL } from "node:url";
|
|||||||
import open from "open";
|
import open from "open";
|
||||||
import crypto from "node:crypto";
|
import crypto from "node:crypto";
|
||||||
import { PublicClientApplication } from "@azure/msal-node";
|
import { PublicClientApplication } from "@azure/msal-node";
|
||||||
|
import fs from "node:fs";
|
||||||
|
import path from "node:path";
|
||||||
|
import os from "node:os";
|
||||||
|
|
||||||
|
function fileCachePlugin(cachePath) {
|
||||||
|
return {
|
||||||
|
beforeCacheAccess: async (ctx) => {
|
||||||
|
if (fs.existsSync(cachePath)) {
|
||||||
|
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()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function generatePkce() {
|
function generatePkce() {
|
||||||
const verifier = crypto.randomBytes(32).toString("base64url"); // 43 chars, valid
|
const verifier = crypto.randomBytes(32).toString("base64url"); // 43 chars, valid
|
||||||
@@ -21,13 +45,36 @@ export async function loginInteractive({ tenantId, clientId, scopes }) {
|
|||||||
if (!Array.isArray(scopes) || scopes.length === 0)
|
if (!Array.isArray(scopes) || scopes.length === 0)
|
||||||
throw new Error("scopes[] is required");
|
throw new Error("scopes[] is required");
|
||||||
|
|
||||||
|
const cachePath = path.join(
|
||||||
|
os.homedir(),
|
||||||
|
".config/azure-node-playground",
|
||||||
|
`${clientId}-token-cache.json`
|
||||||
|
);
|
||||||
|
|
||||||
const pca = new PublicClientApplication({
|
const pca = new PublicClientApplication({
|
||||||
auth: {
|
auth: {
|
||||||
clientId,
|
clientId,
|
||||||
authority: `https://login.microsoftonline.com/${tenantId}`,
|
authority: `https://login.microsoftonline.com/${tenantId}`,
|
||||||
},
|
},
|
||||||
|
cache: {
|
||||||
|
cachePlugin: fileCachePlugin(cachePath),
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const accounts = await pca.getTokenCache().getAllAccounts();
|
||||||
|
|
||||||
|
if (accounts.length > 0) {
|
||||||
|
try {
|
||||||
|
const silentResult = await pca.acquireTokenSilent({
|
||||||
|
account: accounts[0],
|
||||||
|
scopes,
|
||||||
|
});
|
||||||
|
return silentResult;
|
||||||
|
} catch (e) {
|
||||||
|
// proceed to interactive login
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const pkce = generatePkce();
|
const pkce = generatePkce();
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user