Authentication refactoring.

This commit is contained in:
2026-03-11 10:41:42 +01:00
parent d69402a33d
commit b678dd5ace
12 changed files with 214 additions and 152 deletions

View File

@@ -22,14 +22,14 @@ const LOGIN_REQUIRED_MESSAGE = "Login required. Run: sk-az-tools login";
const BROWSER_KEYWORDS = Object.keys(apps).sort();
const OPEN_APPS = apps as Record<string, string | readonly string[]>;
const CHROMIUM_BROWSERS = new Set(["edge", "chrome", "brave"]);
const CONFIG_FILE_NAME = "config";
const SESSION_STATE_NAME = "session-state";
type SessionState = {
activeAccountUpn: string | null;
};
async function readSessionState(): Promise<SessionState> {
const parsed = (await getConfig("sk-az-tools", CONFIG_FILE_NAME)) as { activeAccountUpn?: unknown };
const parsed = (await getConfig("sk-az-tools", SESSION_STATE_NAME)) as { activeAccountUpn?: unknown };
return {
activeAccountUpn:
typeof parsed?.activeAccountUpn === "string"
@@ -39,14 +39,14 @@ async function readSessionState(): Promise<SessionState> {
}
async function writeSessionState(state: SessionState): Promise<void> {
const sessionPath = path.join(getConfigDir("sk-az-tools"), `${CONFIG_FILE_NAME}.json`);
const sessionPath = path.join(getConfigDir("sk-az-tools"), `${SESSION_STATE_NAME}.json`);
await mkdir(path.dirname(sessionPath), { recursive: true });
await writeFile(sessionPath, JSON.stringify(state, null, 2), "utf8");
}
async function clearSessionState(): Promise<void> {
try {
const sessionPath = path.join(getConfigDir("sk-az-tools"), `${CONFIG_FILE_NAME}.json`);
const sessionPath = path.join(getConfigDir("sk-az-tools"), `${SESSION_STATE_NAME}.json`);
await unlink(sessionPath);
} catch (err) {
if ((err as { code?: string } | null)?.code !== "ENOENT") {
@@ -104,19 +104,19 @@ function getBrowserOpenOptions(browser?: string, browserProfile?: string): Param
const browserKeyword = getBrowserKeyword(browser);
if (!CHROMIUM_BROWSERS.has(browserKeyword)) {
throw new Error(
"--browser-profile is supported only with --browser edge|chrome|brave",
"--browser-profile is supported only with --browser-name edge|chrome|brave",
);
}
if (!browserName) {
throw new Error("--browser-profile requires --browser");
throw new Error("--browser-profile requires --browser-name");
}
return {
wait: false,
app: {
name: browserName,
arguments: [`--profile-directory=${browserProfile.trim()}`],
arguments: [`--profile-directory=${browserProfile.trim()}`],
},
};
}
@@ -130,19 +130,18 @@ function validateBrowserOptions(browser?: string, browserProfile?: string): void
const browserKeyword = getBrowserKeyword(browser);
if (!CHROMIUM_BROWSERS.has(browserKeyword)) {
throw new Error(
"--browser-profile is supported only with --browser edge|chrome|brave",
"--browser-profile is supported only with --browser-name edge|chrome|brave",
);
}
}
}
export function parseResources(resourcesCsv?: string): ResourceName[] {
if (!resourcesCsv || resourcesCsv.trim() === "") {
export function parseResources(resourcesInput?: string[]): ResourceName[] {
if (!resourcesInput || resourcesInput.length === 0) {
return [...DEFAULT_RESOURCES];
}
const resources = resourcesCsv
.split(",")
const resources = resourcesInput
.map((item) => item.trim().toLowerCase())
.filter(Boolean);
@@ -317,7 +316,7 @@ export async function loginDeviceCode(
export async function login(
tenantId: string,
clientId: string,
resourcesCsv?: string,
resourcesInput?: string[],
useDeviceCode = false,
noBrowser = false,
browser?: string,
@@ -332,8 +331,8 @@ export async function login(
if (!clientId) throw new Error("clientId is required");
validateBrowserOptions(browser, browserProfile);
const resources = parseResources(resourcesCsv);
const scopes = translateResourceNamesToScopes(resources);
const resources = parseResources(resourcesInput);
const scopes = translateResourceNamesToScopes(resources) as string[];
const pca = await createPca(tenantId, clientId);
const session = await readSessionState();
const preferredAccount = session.activeAccountUpn
@@ -344,6 +343,10 @@ export async function login(
let selectedAccount: AccountInfo | null = preferredAccount;
let token = await acquireTokenWithCache(pca, scopes, selectedAccount);
if (token?.account) {
selectedAccount = token.account;
}
if (!token) {
if (useDeviceCode) {
token = await pca.acquireTokenByDeviceCode({
@@ -378,6 +381,11 @@ export async function login(
});
}
if (!selectedAccount) {
const accounts = await pca.getTokenCache().getAllAccounts();
selectedAccount = accounts[0] ?? null;
}
const activeAccountUpn = selectedAccount?.username ?? null;
if (activeAccountUpn) {
await writeSessionState({ activeAccountUpn });