Repository navigation
Description
Library version used
1.26.0
Java version
11.0.13
Scenario
ConfidentialClient - web site (AcquireTokenByAuthCode)
Is this a new or an existing app?
The app is in production, and I have upgraded to a new version of MSAL
Issue description and reproduction steps
After upgrading from 1.18.0 to 1.26.0 I got a NPE in our application when attempting to log in and get the claims from the ITenantProfile. It seems to me that this is due to a bug. In the class com.microsoft.aad.msal4j.AuthenticationResult, the method public ITenantProfile tenantProfile() always returns null, because the field tenantProfile is always null. This field is assigned in the declaration by result of getTenantProfile(), but this method always returns null because idToken is not yet initialized.
Relevant code snippets
package com.microsoft.aad.msal4j;
import org.junit.Test;
public class MsalTest {
@Test
public void test() {
System.out.println("java version: " + System.getProperty("java.version"));
final String idToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c";
final AccountCacheEntity accountCacheEntity = new AccountCacheEntity() {};
final AuthenticationResult result = new AuthenticationResult("accessToken", 123456, 123456, "refreshToken", 123456L, "familyId", idToken, accountCacheEntity, "environment", "scopes", null, true);
System.out.println("tenantProfile: " + result.tenantProfile());
}
}Expected behavior
The result of the code is:
java version: 11.0.13
tenantProfile: null
The expected behavior is (and in fact was in 1.18.0):
java version: 11.0.13
tenantProfile: com.microsoft.aad.msal4j.TenantProfile@f2ff811
Identity provider
Microsoft Entra ID (Work and School accounts and Personal Microsoft accounts)
Regression
1.18.0
Solution and workarounds
The work-around for getting the claims is parsing them yourself from the idToken instead of getting them from the tenantProfile().
Activity
basitalisandhu commentedon Oct 20, 2026
Confirmed on
dev(30dbbed), and your reading is right. It started in 1.23.0: up to 1.22.0 these were Lombok@Getter(lazy = true)fields, and the Lombok removal (67d3131) kept the initializers without the lazy getter, so they now run before the constructor assignsidToken. The package-privateidTokenObject()has the same problem.account()is fine because it is computed on each call.I opened #1078: both values are derived on access again, with tests that fail on
devand pass with the change.Until a release has it, reading the claims from the ID token yourself works on 1.23.0+. Note that
result.account().getTenantProfiles()does not help here, since the account built for the result has no tenant profiles.This is the same plain decode
tenantProfile()did (JsonHelper.getTokenPayloadClaims); it does not check the signature, so use it only for tokens you just got from MSAL.