{"record":{"id":"cdc363af09e5c8b1","repo":"apereo/cas","slug":"failed-to-acquire-access-token","errorCode":null,"errorMessage":"Failed to acquire access token","messagePattern":"Failed to acquire access token","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"support/cas-server-support-mail-microsoft/src/main/java/org/apereo/cas/mail/MicrosoftEmailSenderCustomizer.java","lineNumber":49,"sourceCode":"        if (microsoft.isDefined() && mailSender instanceof JavaMailSenderImpl impl) {\n            val accessToken = fetchAccessToken();\n            LOGGER.debug(\"Setting accessToken as the password: [{}]\", accessToken);\n            impl.setPassword(accessToken);\n        }\n    }\n\n    protected String fetchAccessToken() {\n        try {\n            val microsoft = casProperties.getEmailProvider().getMicrosoft();\n            val clientCredentialParameters = ClientCredentialParameters.builder(microsoft.getScopes()).build();\n            val clientApplication = ConfidentialClientApplication\n                .builder(SpringExpressionLanguageValueResolver.getInstance().resolve(microsoft.getClientId()),\n                    ClientCredentialFactory.createFromSecret(SpringExpressionLanguageValueResolver.getInstance().resolve(microsoft.getClientSecret())))\n                .authority(\"https://login.microsoftonline.com/%s\".formatted(SpringExpressionLanguageValueResolver.getInstance().resolve(microsoft.getTenantId())))\n                .build();\n            return clientApplication.acquireToken(clientCredentialParameters).get().accessToken();\n        } catch (final Exception e) {\n            throw new RuntimeException(\"Failed to acquire access token\", e);\n        }\n    }\n}\n","sourceCodeStart":31,"sourceCodeEnd":53,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-mail-microsoft/src/main/java/org/apereo/cas/mail/MicrosoftEmailSenderCustomizer.java#L31-L53","documentation":"MicrosoftEmailSenderCustomizer obtains an OAuth2 client-credentials access token from Azure AD (MSAL4J ConfidentialClientApplication) so emails can be sent via Microsoft Graph. Any failure in the async acquireToken call — HTTP errors, bad tenant/client id/secret, network issues — is caught and rethrown as this RuntimeException with the original cause attached.","triggerScenarios":"Calling accessToken() during email-sender customization when msal4j's clientApplication.acquireToken(clientCredentialParameters).get() throws or completes exceptionally: wrong tenantId/clientId/clientSecret, Azure AD unreachable, Conditional Access blocking the app, or an expired/revoked secret.","commonSituations":"Expired or rotated Azure client secret not updated in CAS config; wrong tenant id; outbound firewall/proxy blocking login.microsoftonline.com; app not granted Mail.Send application permission; tenant misconfigured for the authority URL.","solutions":["Inspect the wrapped cause (e.getCause()) — it contains MSAL's exact failure (invalid_client, AADSTS error code, IOException)","Verify cas.email.microsoft.client-id, client-secret and tenant-id are correct and the secret has not expired in Azure Portal (App registrations > Certificates & secrets)","Ensure the server can reach https://login.microsoftonline.com (proxy/firewall/DNS)","Grant the app the Mail.Send application permission and admin consent","Check the authority URL tenant placeholder resolves to a real tenant id"],"exampleFix":"// before\ncas.email.microsoft.client-secret=${OLD_SECRET}\n\n// after  (update Azure portal secret & config)\ncas.email.microsoft.client-id=00000000-0000-0000-0000-000000000000\ncas.email.microsoft.client-secret=NEW_SECRET_VALUE\ncas.email.microsoft.tenant-id=11111111-1111-1111-1111-111111111111","handlingStrategy":"try-catch","validationCode":"// preflight: verify required Microsoft mail config is present\nif (StringUtils.isBlank(clientId) || StringUtils.isBlank(clientSecret) || StringUtils.isBlank(tenantId)) {\n    throw new IllegalStateException(\"Microsoft mail sender requires client-id, client-secret and tenant-id\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    return clientApplication.acquireToken(params).get().accessToken();\n} catch (ExecutionException | InterruptedException e) {\n    logger.error(\"MSAL token acquisition failed: {}\", e.getCause());\n    throw new MailSenderException(\"Failed to acquire access token\", e);\n}","preventionTips":["Monitor Azure AD app secret expiry and rotate before it lapses","Grant Mail.Send application permission with admin consent before going live","Verify outbound connectivity to login.microsoftonline.com from the CAS host","Always log the MSAL cause, not just the wrapper message"],"tags":["azure-ad","oauth2","email","network"],"backgroundTag":"oauth-token-exchange-failed","analyzedSha":"e7288fc434b4f4505b8452e1a57e8fb3111bb863","analyzedAt":"2026-09-08T15:39:16.015Z","contentChangedAt":"2026-09-08T15:39:16.015Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}