redis/node-redis · error · Error
MSAL_CLIENT_ID and MSAL_TENANT_ID environment variables…
Error message
MSAL_CLIENT_ID and MSAL_TENANT_ID environment variables must be set
What it means
Thrown synchronously at module load by the interactive-browser sample app when either MSAL_CLIENT_ID or MSAL_TENANT_ID is absent from the environment. Both values are required to construct an InteractiveBrowserCredential against a Microsoft Entra ID (Azure AD) app registration. The app calls dotenv.config() earlier in the same file, so values may come from a .env file in the working directory or from the process environment.
Solutions
- Create a .env file in packages/entraid (or the repo root, depending on where you launch) with MSAL_CLIENT_ID and MSAL_TENANT_ID copied from your Azure app registration
- Export them in the shell before launching: export MSAL_CLIENT_ID=<client-id> && export MSAL_TENANT_ID=<tenant-id>
- Register an application in the Azure Entra ID portal to obtain a client (application) ID and note the directory (tenant) ID if you do not yet have them
Example fix
// before — missing vars, process exits on import // (no .env, no shell exports) // after — packages/entraid/.env // MSAL_CLIENT_ID=11111111-2222-3333-4444-555555555555 // MSAL_TENANT_ID=aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee // SESSION_SECRET=any-long-random-string
Defensive patterns
Strategy: validation
Validate before calling
function assertEntraIdEnv(): void {
const missing: string[] = [];
if (!process.env.MSAL_CLIENT_ID) missing.push('MSAL_CLIENT_ID');
if (!process.env.MSAL_TENANT_ID) missing.push('MSAL_TENANT_ID');
if (missing.length) {
throw new Error(`Missing required env vars: ${missing.join(', ')}`);
}
}
// call before app.listen
assertEntraIdEnv(); Type guard
function hasEntraIdEnv(env: NodeJS.ProcessEnv): env is NodeJS.ProcessEnv & {
MSAL_CLIENT_ID: string;
MSAL_TENANT_ID: string;
} {
return typeof env.MSAL_CLIENT_ID === 'string' && env.MSAL_CLIENT_ID.length > 0
&& typeof env.MSAL_TENANT_ID === 'string' && env.MSAL_TENANT_ID.length > 0;
} Prevention
- Commit a .env.example listing MSAL_CLIENT_ID, MSAL_TENANT_ID, and SESSION_SECRET so new contributors copy it
- Run the env check in a prelaunch script so failures are obvious before the server binds a port
- In CI, fail the job early if the Azure secrets are not injected rather than letting the sample crash on import
When it happens
Trigger: Running the sample (e.g. `npx tsx packages/entraid/samples/interactive-browser/index.ts` or the built JS) without MSAL_CLIENT_ID/MSAL_TENANT_ID set in the shell or in a .env file resolvable from the process working directory.
Common situations: Fresh clone with no .env file copied from .env.example; CI pipeline that forgot to inject the Azure secrets; running from a different working directory so dotenv cannot locate .env; app registration not yet created in Entra ID.
Related errors
- Invalid authority configuration
- Invalid token response
- MSAL_CLIENT_ID and MSAL_TENANT_ID environment variables…
- SESSION_SECRET environment variable must be set
- SESSION_SECRET environment variable must be set
AI-assisted analysis of redis/node-redis@90fd0652bc (2026-08-11).
Data as JSON: /api/errors/7f4aee2e28c6c617.
Report an issue: GitHub.
Appendix: source
Thrown at packages/entraid/samples/interactive-browser/index.ts:30
const app = express();
const sessionConfig = {
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {
secure: process.env.NODE_ENV === 'production', // Only use secure in production
httpOnly: true,
sameSite: 'lax',
maxAge: 3600000 // 1 hour
}
} as const;
app.use(session(sessionConfig));
if (!process.env.MSAL_CLIENT_ID || !process.env.MSAL_TENANT_ID) {
throw new Error('MSAL_CLIENT_ID and MSAL_TENANT_ID environment variables must be set');
}
app.get('/login', async (req: Request, res: Response) => {
try {
// Create an instance of InteractiveBrowserCredential
const credential = new InteractiveBrowserCredential({
clientId: process.env.MSAL_CLIENT_ID!,
tenantId: process.env.MSAL_TENANT_ID!,
loginStyle: 'popup',
redirectUri: 'http://localhost:3000/redirect'
});
// Create Redis client using the EntraID credentials provider
const entraidCredentialsProvider = EntraIdCredentialsProviderFactory.createForDefaultAzureCredential({
credential,
scopes: ['user.read'],
tokenManagerConfig: DEFAULT_TOKEN_MANAGER_CONFIGView on GitHub (pinned to 90fd0652bc)