{"record":{"id":"5a550ba95e753416","repo":"redis/node-redis","slug":"invalid-token-response","errorCode":null,"errorMessage":"Invalid token response","messagePattern":"Invalid token response","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/entraid/lib/msal-identity-provider.ts","lineNumber":17,"sourceCode":"import {\n  AuthenticationResult\n} from '@azure/msal-node';\nimport { IdentityProvider, TokenResponse } from '@redis/client/dist/lib/authx';\n\nexport class MSALIdentityProvider implements IdentityProvider<AuthenticationResult> {\n  private readonly getToken: () => Promise<AuthenticationResult>;\n\n  constructor(getToken: () => Promise<AuthenticationResult>) {\n    this.getToken = getToken;\n  }\n\n  async requestToken(): Promise<TokenResponse<AuthenticationResult>> {\n    const result = await this.getToken();\n\n    if (!result?.accessToken || !result?.expiresOn) {\n      throw new Error('Invalid token response');\n    }\n    return {\n      token: result,\n      ttlMs: result.expiresOn.getTime() - Date.now()\n    };\n  }\n\n}\n","sourceCodeStart":1,"sourceCodeEnd":26,"githubUrl":"https://github.com/redis/node-redis/blob/90fd0652bc3f2a0a1b2f79fa9096b02a86b0ac58/packages/entraid/lib/msal-identity-provider.ts#L1-L26","documentation":"`MSALIdentityProvider.requestToken()` calls the injected MSAL `getToken()` and requires the result to have both `accessToken` and `expiresOn`; if either is missing (or the result is null/undefined), it throws 'Invalid token response' rather than handing an incomplete token downstream. The subsequent `ttlMs` math (`expiresOn.getTime()`) would also throw on a non-Date, so the guard prevents that.","triggerScenarios":"MSAL `acquireToken*` returning a result lacking `accessToken` or `expiresOn` (null/undefined or a Partial), passed into the provider. Happens on silent-acquire failures that resolve instead of reject, or malformed cached results.","commonSituations":"Wrong/missing scopes; invalid client credentials; MSAL token cache corruption; account not present for silent acquisition; misconfigured `getToken` callback.","solutions":["Verify MSAL configuration (clientId, tenant, authority, scopes, redirect).","Ensure the credentials/account used for silent acquisition exist and are valid.","Make the injected `getToken` reject (not resolve empty) on real failures so requestToken surfaces the underlying MSAL error.","Clear/rebuild the MSAL token cache if corrupted."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"function isValidTokenResult(r: unknown): r is { accessToken: string; expiresOn: Date } {\n  return !!r && typeof (r as any)?.accessToken === 'string' && (r as any)?.expiresOn instanceof Date;\n}","typeGuard":"function isValidTokenResult(r: unknown): r is { accessToken: string; expiresOn: Date } {\n  return !!r && typeof (r as any)?.accessToken === 'string' && (r as any)?.expiresOn instanceof Date;\n}","tryCatchPattern":"try {\n  return await provider.requestToken();\n} catch (e) {\n  if (String(e).includes('Invalid token response')) {\n    // surface underlying MSAL error by retrying interactive acquisition, or rethrow with context\n    throw new Error('MSAL returned an incomplete token; check scopes/credentials/account', { cause: e });\n  }\n  throw e;\n}","preventionTips":["Make the injected getToken reject on real failures so requestToken surfaces the true cause.","Validate scopes/clientId/tenant and account presence before silent acquisition."],"tags":["entraid","auth","msal","token","azure"],"backgroundTag":null,"analyzedSha":"90fd0652bc3f2a0a1b2f79fa9096b02a86b0ac58","analyzedAt":"2026-08-11T15:37:21.243Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}