用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/fabioc-aloha/Alex_Skill_Mall --skill msal-singleton-pattern命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
基于 SOC 职业分类
| name | msal-singleton-pattern |
| description | Time Saved: 1+ hour debugging silent auth failures |
| lastReviewed | 2026-04-30T00:00:00.000Z |
Category: Azure Time Saved: 1+ hour debugging silent auth failures Battle-tested: Yes — HeadstartWebsite, Next.js + Azure projects
Your React/Next.js app uses MSAL.js for Azure AD authentication. Login works, but token refresh fails silently. Sometimes users get logged out randomly. The console shows cryptic "interaction_in_progress" errors.
MSAL.js PublicClientApplication maintains an internal token cache and tracks in-flight auth requests. Creating multiple instances causes:
acquireTokenSilentInitialize MSAL once, share the singleton across your entire app
// ❌ BROKEN — new instance on every import/render
function getAuth() {
return new PublicClientApplication(msalConfig);
}
// ✅ CORRECT — module-level singleton with async init
let msalInstance: PublicClientApplication | null = null;
let initPromise: Promise<PublicClientApplication> | null = null;
export async function getMsalInstance(): Promise<PublicClientApplication> {
if (msalInstance) return msalInstance;
if (!initPromise) {
initPromise = (async () => {
const instance = new PublicClientApplication(msalConfig);
await instance.initialize(); // Required in MSAL.js 2.x+
msalInstance = instance;
return instance;
})();
}
return initPromise;
}
// MsalProvider.tsx
import { MsalProvider } from '@azure/msal-react';
import { getMsalInstance } from './msal-singleton';
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [instance, setInstance] = useState<PublicClientApplication | null>(null);
useEffect(() => {
getMsalInstance().then(setInstance);
}, []);
if (!instance) return <Loading />;
return <MsalProvider instance={instance}>{children}</MsalProvider>;
}
// app/providers.tsx
'use client';
import { MsalProvider } from '@azure/msal-react';
import { getMsalInstance } from '@/lib/msal-singleton';
export function Providers({ children }: { children: React.ReactNode }) {
const [instance, setInstance] = useState<IPublicClientApplication | null>(null);
useEffect(() => {
getMsalInstance().then(setInstance);
}, []);
if (!instance) return null;
return <MsalProvider instance={instance}>{children}</MsalProvider>;
}
| Mistake | Symptom | Fix |
|---|---|---|
| New instance per request | Token cache miss, re-auth required | Use singleton |
Missing initialize() | Silent failures in MSAL 2.x+ | Call and await initialize() |
| Instance in component state | Re-created on re-render | Module-level singleton |
Multiple MsalProviders | "interaction_in_progress" | Single provider at app root |
// Add to singleton for debugging
export function getMsalDebugInfo() {
return {
instanceExists: !!msalInstance,
accounts: msalInstance?.getAllAccounts() ?? [],
cacheSize: Object.keys(msalInstance?.getTokenCache()?.serialize() ?? {}).length,
};
}
If accounts is empty after login, the singleton isn't being used consistently.
Source: Promoted from AI-Memory global-knowledge.md (2026-04-27)