55
66import java .util .Map ;
77import java .util .Set ;
8+ import java .util .SortedMap ;
89import java .util .TreeMap ;
910
1011import static com .microsoft .aad .msal4j .ParameterValidationUtils .validateNotNull ;
@@ -31,6 +32,15 @@ public class ClientCredentialParameters implements IAcquireTokenParameters {
3132
3233 private String fmiPath ;
3334
35+ // Generic extended cache key components. Any parameter that should influence token cache
36+ // isolation adds an entry here (e.g., fmi_path, credential_fmi_path). The hash of these
37+ // components is used as part of the cache key for AccessToken_Extended entries.
38+ // Matches MSAL .NET's AdditionalCacheKeyComponents / CacheKeyComponents pattern.
39+ private SortedMap <String , String > cacheKeyComponents ;
40+
41+ // Memoized hash of cacheKeyComponents (computed once since parameters are immutable).
42+ private String extCacheKeyHashCache ;
43+
3444 private ClientCredentialParameters (Set <String > scopes , Boolean skipCache , ClaimsRequest claims , Map <String , String > extraHttpHeaders , Map <String , String > extraQueryParameters , String tenant , IClientCredential clientCredential , String fmiPath ) {
3545 this .scopes = scopes ;
3646 this .skipCache = skipCache ;
@@ -40,6 +50,9 @@ private ClientCredentialParameters(Set<String> scopes, Boolean skipCache, Claims
4050 this .tenant = tenant ;
4151 this .clientCredential = clientCredential ;
4252 this .fmiPath = fmiPath ;
53+
54+ // Build cache key components from any parameters that require cache isolation.
55+ this .cacheKeyComponents = buildCacheKeyComponents ();
4356 }
4457
4558 private static ClientCredentialParametersBuilder builder () {
@@ -103,26 +116,43 @@ public String fmiPath() {
103116 }
104117
105118 /**
106- * Computes the extended cache key hash for this request's fmi_path, if set.
107- * Returns an empty string if fmiPath is not set.
108- * This is the single source of truth for the fmi_path cache key hash computation,
109- * used by both cache writes (TokenCache) and cache reads (silent lookup).
110- * The result is memoized since ClientCredentialParameters is immutable after construction.
119+ * Builds the sorted map of cache key components from the parameters that require
120+ * cache isolation. Returns null if no components are present.
121+ * <p>
122+ * This is the single place where parameters contribute to the extended cache key.
123+ * To add a new cache key component, add an entry here — the hash computation and
124+ * cache read/write logic are fully generic and require no changes.
111125 */
112- private String fmiCacheKeyHashCache ;
113-
114- String computeFmiCacheKeyHash () {
115- if (fmiCacheKeyHashCache != null ) {
116- return fmiCacheKeyHashCache ;
117- }
126+ private SortedMap <String , String > buildCacheKeyComponents () {
127+ TreeMap <String , String > components = null ;
118128 if (!StringHelper .isBlank (fmiPath )) {
119- TreeMap < String , String > components = new TreeMap <>();
129+ components = new TreeMap <>();
120130 components .put ("fmi_path" , fmiPath );
121- fmiCacheKeyHashCache = StringHelper .computeExtCacheKeyHash (components );
122- } else {
123- fmiCacheKeyHashCache = "" ;
124131 }
125- return fmiCacheKeyHashCache ;
132+ return components ;
133+ }
134+
135+ /**
136+ * Returns the extended cache key components for this request, if any.
137+ * Used by {@link TokenCache} for both cache writes and reads.
138+ */
139+ SortedMap <String , String > cacheKeyComponents () {
140+ return this .cacheKeyComponents ;
141+ }
142+
143+ /**
144+ * Computes the extended cache key hash from all cache key components.
145+ * Returns an empty string if no components are present.
146+ * <p>
147+ * The result is memoized since ClientCredentialParameters is immutable after construction.
148+ * Used by both cache writes ({@link TokenCache}) and cache reads (silent lookup).
149+ */
150+ String computeExtCacheKeyHash () {
151+ if (extCacheKeyHashCache != null ) {
152+ return extCacheKeyHashCache ;
153+ }
154+ extCacheKeyHashCache = StringHelper .computeExtCacheKeyHash (cacheKeyComponents );
155+ return extCacheKeyHashCache ;
126156 }
127157
128158 public static class ClientCredentialParametersBuilder {
0 commit comments