Skip to content

Commit a69a529

Browse files
authored
[Identity] Fix token refresh issue for MSA accounts (Azure#15959)
* [Identity] Fix token refresh issue for MSA accounts * fixing tests MockMsalPublicClient * fix to allow explicitly specifying tenantId
1 parent 2d44823 commit a69a529

File tree

5 files changed

+43
-2
lines changed

5 files changed

+43
-2
lines changed

sdk/identity/Azure.Identity/src/DeviceCodeCredential.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ private async ValueTask<AccessToken> GetTokenImplAsync(bool async, TokenRequestC
198198
{
199199
try
200200
{
201-
AuthenticationResult result = await Client.AcquireTokenSilentAsync(requestContext.Scopes, (AuthenticationAccount)Record, async, cancellationToken).ConfigureAwait(false);
201+
AuthenticationResult result = await Client.AcquireTokenSilentAsync(requestContext.Scopes, Record, async, cancellationToken).ConfigureAwait(false);
202202

203203
return scope.Succeeded(new AccessToken(result.AccessToken, result.ExpiresOn));
204204
}

sdk/identity/Azure.Identity/src/InteractiveBrowserCredential.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ private async ValueTask<AccessToken> GetTokenImplAsync(bool async, TokenRequestC
181181
{
182182
try
183183
{
184-
AuthenticationResult result = await Client.AcquireTokenSilentAsync(requestContext.Scopes, (AuthenticationAccount)Record, async, cancellationToken).ConfigureAwait(false);
184+
AuthenticationResult result = await Client.AcquireTokenSilentAsync(requestContext.Scopes, Record, async, cancellationToken).ConfigureAwait(false);
185185

186186
return scope.Succeeded(new AccessToken(result.AccessToken, result.ExpiresOn));
187187
}

sdk/identity/Azure.Identity/src/MsalPublicClient.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,17 @@ public virtual async ValueTask<AuthenticationResult> AcquireTokenSilentAsync(str
5252
IPublicClientApplication client = await GetClientAsync(async, cancellationToken).ConfigureAwait(false);
5353
return await client.AcquireTokenSilent(scopes, account).ExecuteAsync(async, cancellationToken).ConfigureAwait(false);
5454
}
55+
public virtual async ValueTask<AuthenticationResult> AcquireTokenSilentAsync(string[] scopes, AuthenticationRecord record, bool async, CancellationToken cancellationToken)
56+
{
57+
IPublicClientApplication client = await GetClientAsync(async, cancellationToken).ConfigureAwait(false);
58+
59+
// if the user specified a TenantId when they created the client we want to authenticate to that tenant.
60+
// otherwise we should authenticate with the tenant specified by the authentication record since that's the tenant the
61+
// user authenticated to originally.
62+
return await client.AcquireTokenSilent(scopes, (AuthenticationAccount)record)
63+
.WithAuthority(Pipeline.AuthorityHost.AbsoluteUri, TenantId ?? record.TenantId)
64+
.ExecuteAsync(async, cancellationToken).ConfigureAwait(false);
65+
}
5566

5667
public virtual async ValueTask<AuthenticationResult> AcquireTokenInteractiveAsync(string[] scopes, Prompt prompt, bool async, CancellationToken cancellationToken)
5768
{

sdk/identity/Azure.Identity/tests/InteractiveBrowserCredentialLiveTests.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,5 +85,23 @@ public async Task AuthenticateWithSharedTokenCacheAsync()
8585

8686
Assert.NotNull(token.Token);
8787
}
88+
89+
[Test]
90+
[Ignore("This test is an integration test which can only be run with user interaction")]
91+
// This test should be run with an MSA account to validate that the refresh for MSA accounts works properly
92+
public async Task AuthenticateWithMSAWithSubsequentSilentRefresh()
93+
{
94+
var cred = new InteractiveBrowserCredential();
95+
96+
// this should pop browser
97+
var authRecord = await cred.AuthenticateAsync();
98+
99+
Assert.NotNull(authRecord);
100+
101+
// this should not pop browser
102+
AccessToken token = await cred.GetTokenAsync(new TokenRequestContext(new string[] { "https://vault.azure.net/.default" })).ConfigureAwait(false);
103+
104+
Assert.NotNull(token.Token);
105+
}
88106
}
89107
}

sdk/identity/Azure.Identity/tests/Mock/MockMsalPublicClient.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,18 @@ public override ValueTask<AuthenticationResult> AcquireTokenSilentAsync(string[]
7373
throw new NotImplementedException();
7474
}
7575

76+
public override ValueTask<AuthenticationResult> AcquireTokenSilentAsync(string[] scopes, AuthenticationRecord record, bool async, CancellationToken cancellationToken)
77+
{
78+
Func<string[], AuthenticationResult> factory = SilentAuthFactory ?? AuthFactory;
79+
80+
if (factory != null)
81+
{
82+
return new ValueTask<AuthenticationResult>(factory(scopes));
83+
}
84+
85+
throw new NotImplementedException();
86+
}
87+
7688
public override ValueTask<AuthenticationResult> AcquireTokenWithDeviceCodeAsync(string[] scopes, Func<DeviceCodeResult, Task> deviceCodeCallback, bool async, CancellationToken cancellationToken)
7789
{
7890
Func<string[], AuthenticationResult> factory = DeviceCodeAuthFactory ?? AuthFactory;

0 commit comments

Comments
 (0)