1313class AcquireTokenSilentSupplier extends AuthenticationResultSupplier {
1414
1515 private SilentRequest silentRequest ;
16+ protected static final int ACCESS_TOKEN_EXPIRE_BUFFER_IN_SEC = 5 * 60 ;
1617
1718 AcquireTokenSilentSupplier (AbstractApplicationBase clientApplication , SilentRequest silentRequest ) {
1819 super (clientApplication , silentRequest );
@@ -22,6 +23,7 @@ class AcquireTokenSilentSupplier extends AuthenticationResultSupplier {
2223
2324 @ Override
2425 AuthenticationResult execute () throws Exception {
26+ boolean shouldRefresh ;
2527 Authority requestAuthority = silentRequest .requestAuthority ();
2628 if (requestAuthority .authorityType != AuthorityType .B2C ) {
2729 requestAuthority =
@@ -53,29 +55,9 @@ AuthenticationResult execute() throws Exception {
5355 clientApplication .serviceBundle ().getServerSideTelemetry ().incrementSilentSuccessfulCount ();
5456 }
5557
56- //Determine if the current token needs to be refreshed according to the refresh_in value
57- long currTimeStampSec = new Date ().getTime () / 1000 ;
58- boolean afterRefreshOn = res .refreshOn () != null && res .refreshOn () > 0 &&
59- res .refreshOn () < currTimeStampSec && res .expiresOn () >= currTimeStampSec ;
60-
61- if (silentRequest .parameters ().forceRefresh () || afterRefreshOn || StringHelper .isBlank (res .accessToken ())) {
62-
63- //As of version 3 of the telemetry schema, there is a field for collecting data about why a token was refreshed,
64- // so here we set the telemetry value based on the cause of the refresh
65- if (silentRequest .parameters ().forceRefresh ()) {
66- clientApplication .serviceBundle ().getServerSideTelemetry ().getCurrentRequest ().cacheInfo (
67- CacheTelemetry .REFRESH_FORCE_REFRESH .telemetryValue );
68- } else if (afterRefreshOn ) {
69- clientApplication .serviceBundle ().getServerSideTelemetry ().getCurrentRequest ().cacheInfo (
70- CacheTelemetry .REFRESH_REFRESH_IN .telemetryValue );
71- } else if (res .expiresOn () < currTimeStampSec ) {
72- clientApplication .serviceBundle ().getServerSideTelemetry ().getCurrentRequest ().cacheInfo (
73- CacheTelemetry .REFRESH_ACCESS_TOKEN_EXPIRED .telemetryValue );
74- } else if (StringHelper .isBlank (res .accessToken ())) {
75- clientApplication .serviceBundle ().getServerSideTelemetry ().getCurrentRequest ().cacheInfo (
76- CacheTelemetry .REFRESH_NO_ACCESS_TOKEN .telemetryValue );
77- }
58+ shouldRefresh = shouldRefresh (silentRequest .parameters (), res );
7859
60+ if (shouldRefresh || clientApplication .serviceBundle ().getServerSideTelemetry ().getCurrentRequest ().cacheInfo () == CacheTelemetry .REFRESH_REFRESH_IN .telemetryValue ) {
7961 if (!StringHelper .isBlank (res .refreshToken ())) {
8062 //There are certain scenarios where the cached authority may differ from the client app's authority,
8163 // such as when a request is instance aware. Unless overridden by SilentParameters.authorityUrl, the
@@ -84,29 +66,7 @@ AuthenticationResult execute() throws Exception {
8466 requestAuthority = Authority .createAuthority (new URL (requestAuthority .authority ().replace (requestAuthority .host (),
8567 res .account ().environment ())));
8668 }
87-
88- RefreshTokenRequest refreshTokenRequest = new RefreshTokenRequest (
89- RefreshTokenParameters .builder (silentRequest .parameters ().scopes (), res .refreshToken ()).build (),
90- silentRequest .application (),
91- silentRequest .requestContext (),
92- silentRequest );
93-
94- AcquireTokenByAuthorizationGrantSupplier acquireTokenByAuthorisationGrantSupplier =
95- new AcquireTokenByAuthorizationGrantSupplier (clientApplication , refreshTokenRequest , requestAuthority );
96-
97- try {
98- res = acquireTokenByAuthorisationGrantSupplier .execute ();
99-
100- res .metadata ().tokenSource (TokenSource .IDENTITY_PROVIDER );
101-
102- log .info ("Access token refreshed successfully." );
103- } catch (MsalServiceException ex ) {
104- //If the token refresh attempt threw a MsalServiceException but the refresh attempt was done
105- // only because of refreshOn, then simply return the existing cached token
106- if (afterRefreshOn && !(silentRequest .parameters ().forceRefresh () || StringHelper .isBlank (res .accessToken ()))) {
107- return res ;
108- } else throw ex ;
109- }
69+ res = makeRefreshRequest (res , requestAuthority );
11070 } else {
11171 res = null ;
11272 }
@@ -120,4 +80,81 @@ AuthenticationResult execute() throws Exception {
12080
12181 return res ;
12282 }
83+
84+ private AuthenticationResult makeRefreshRequest (AuthenticationResult cachedResult , Authority requestAuthority ) throws Exception {
85+ RefreshTokenRequest refreshTokenRequest = new RefreshTokenRequest (
86+ RefreshTokenParameters .builder (silentRequest .parameters ().scopes (), cachedResult .refreshToken ()).build (),
87+ silentRequest .application (),
88+ silentRequest .requestContext (),
89+ silentRequest );
90+
91+ AcquireTokenByAuthorizationGrantSupplier acquireTokenByAuthorisationGrantSupplier =
92+ new AcquireTokenByAuthorizationGrantSupplier (clientApplication , refreshTokenRequest , requestAuthority );
93+
94+ try {
95+ AuthenticationResult refreshedResult = acquireTokenByAuthorisationGrantSupplier .execute ();
96+
97+ refreshedResult .metadata ().tokenSource (TokenSource .IDENTITY_PROVIDER );
98+
99+ log .info ("Access token refreshed successfully." );
100+ return refreshedResult ;
101+ } catch (MsalServiceException ex ) {
102+ //If the token refresh attempt threw a MsalServiceException but the refresh attempt was done
103+ // only because of refreshOn, then simply return the existing cached token rather than throw an exception
104+ if (clientApplication .serviceBundle ().getServerSideTelemetry ().getCurrentRequest ().cacheInfo () == CacheTelemetry .REFRESH_REFRESH_IN .telemetryValue ) {
105+ return cachedResult ;
106+ }
107+ throw ex ;
108+ }
109+ }
110+
111+ //Handles any logic to determine if a token should be refreshed, based on the request parameters and the status of cached tokens
112+ private boolean shouldRefresh (SilentParameters parameters , AuthenticationResult cachedResult ) {
113+
114+ //If forceRefresh is true, no reason to check any other option
115+ if (parameters .forceRefresh ()) {
116+ setCacheTelemetry (CacheTelemetry .REFRESH_FORCE_REFRESH .telemetryValue );
117+ log .debug ("Refreshing access token because forceRefresh parameter is true." );
118+ return true ;
119+ }
120+
121+ //If the request contains claims then the token should be refreshed, to ensure that the returned token has the correct claims
122+ // Note: these are the types of claims found in (for example) a claims challenge, and do not include client capabilities
123+ if (parameters .claims () != null ) {
124+ setCacheTelemetry (CacheTelemetry .REFRESH_FORCE_REFRESH .telemetryValue );
125+ log .debug ("Refreshing access token because the claims parameter is not null." );
126+ return true ;
127+ }
128+
129+ long currTimeStampSec = new Date ().getTime () / 1000 ;
130+
131+ //If the access token is expired or within 5 minutes of becoming expired, refresh it
132+ if (!StringHelper .isBlank (cachedResult .accessToken ()) && cachedResult .expiresOn () < (currTimeStampSec - ACCESS_TOKEN_EXPIRE_BUFFER_IN_SEC )) {
133+ setCacheTelemetry (CacheTelemetry .REFRESH_ACCESS_TOKEN_EXPIRED .telemetryValue );
134+ log .debug ("Refreshing access token because it is expired." );
135+ return true ;
136+ }
137+
138+ //Certain long-lived tokens will have a 'refresh on' time that indicates a refresh should be attempted long before the token would expire
139+ if (!StringHelper .isBlank (cachedResult .accessToken ()) &&
140+ cachedResult .refreshOn () != null && cachedResult .refreshOn () > 0 &&
141+ cachedResult .refreshOn () < currTimeStampSec && cachedResult .expiresOn () >= (currTimeStampSec + ACCESS_TOKEN_EXPIRE_BUFFER_IN_SEC )){
142+ setCacheTelemetry (CacheTelemetry .REFRESH_REFRESH_IN .telemetryValue );
143+ log .debug ("Attempting to refresh access token because it is after the refreshOn time." );
144+ return true ;
145+ }
146+
147+ //If there is a refresh token but no access token, we should use the refresh token to get the access token
148+ if (StringHelper .isBlank (cachedResult .accessToken ()) && !StringHelper .isBlank (cachedResult .refreshToken ())) {
149+ setCacheTelemetry (CacheTelemetry .REFRESH_NO_ACCESS_TOKEN .telemetryValue );
150+ log .debug ("Refreshing access token because it was missing from the cache." );
151+ return true ;
152+ }
153+
154+ return false ;
155+ }
156+
157+ private void setCacheTelemetry (int cacheInfoValue ){
158+ clientApplication .serviceBundle ().getServerSideTelemetry ().getCurrentRequest ().cacheInfo (cacheInfoValue );
159+ }
123160}
0 commit comments