Skip to content

Commit 8a1658e

Browse files
authored
Add support for browser auth timeout (#189)
1 parent 47e4ac2 commit 8a1658e

File tree

3 files changed

+59
-2
lines changed

3 files changed

+59
-2
lines changed

.vscode/cspell.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"LINUXOS",
4040
"LINUXPOOL",
4141
"LINUXVMIMAGE",
42+
"msal",
4243
"mysvc",
4344
"mycluster",
4445
"MACOS",

src/Services/Azure/Authentication/CustomChainedCredential.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public override ValueTask<AccessToken> GetTokenAsync(TokenRequestContext request
3535
}
3636

3737
private const string AuthenticationRecordEnvVarName = "AZURE_MCP_AUTHENTICATION_RECORD";
38+
private const string BrowserAuthenticationTimeoutEnvVarName = "AZURE_MCP_BROWSER_AUTH_TIMEOUT_SECONDS";
3839
private const string OnlyUseBrokerCredentialEnvVarName = "AZURE_MCP_ONLY_USE_BROKER_CREDENTIAL";
3940
private const string ClientIdEnvVarName = "AZURE_MCP_CLIENT_ID";
4041
private const string IncludeProductionCredentialEnvVarName = "AZURE_MCP_INCLUDE_PRODUCTION_CREDENTIALS";
@@ -67,7 +68,7 @@ private static ChainedTokenCredential CreateChainedCredential(string? tenantId)
6768

6869
private static string TokenCacheName = "azure-mcp-msal.cache";
6970

70-
private static InteractiveBrowserCredential CreateBrowserCredential(string? tenantId, AuthenticationRecord? authRecord)
71+
private static TokenCredential CreateBrowserCredential(string? tenantId, AuthenticationRecord? authRecord)
7172
{
7273
string? clientId = Environment.GetEnvironmentVariable(ClientIdEnvVarName);
7374

@@ -89,7 +90,16 @@ private static InteractiveBrowserCredential CreateBrowserCredential(string? tena
8990
brokerOptions.ClientId = clientId;
9091
}
9192

92-
return new(brokerOptions);
93+
var browserCredential = new InteractiveBrowserCredential(brokerOptions);
94+
95+
// Check for timeout value in the environment variable
96+
string? timeoutValue = Environment.GetEnvironmentVariable(BrowserAuthenticationTimeoutEnvVarName);
97+
int timeoutSeconds = 300; // Default to 300 seconds (5 minutes)
98+
if (!string.IsNullOrEmpty(timeoutValue) && int.TryParse(timeoutValue, out int parsedTimeout) && parsedTimeout > 0)
99+
{
100+
timeoutSeconds = parsedTimeout;
101+
}
102+
return new TimeoutTokenCredential(browserCredential, TimeSpan.FromSeconds(timeoutSeconds));
93103
}
94104

95105
private static DefaultAzureCredential CreateDefaultCredential(string? tenantId)
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
using Azure.Core;
5+
6+
public class TimeoutTokenCredential : TokenCredential
7+
{
8+
private readonly TokenCredential _innerCredential;
9+
private readonly TimeSpan _timeout;
10+
11+
public TimeoutTokenCredential(TokenCredential innerCredential, TimeSpan timeout)
12+
{
13+
_innerCredential = innerCredential;
14+
_timeout = timeout;
15+
}
16+
17+
public override AccessToken GetToken(TokenRequestContext requestContext, CancellationToken cancellationToken)
18+
{
19+
using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
20+
cts.CancelAfter(_timeout);
21+
22+
try
23+
{
24+
return _innerCredential.GetToken(requestContext, cts.Token);
25+
}
26+
catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested)
27+
{
28+
throw new TimeoutException($"Authentication timed out after {_timeout.TotalSeconds} seconds.");
29+
}
30+
}
31+
32+
public override async ValueTask<AccessToken> GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken)
33+
{
34+
using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
35+
cts.CancelAfter(_timeout);
36+
37+
try
38+
{
39+
return await _innerCredential.GetTokenAsync(requestContext, cts.Token).ConfigureAwait(false);
40+
}
41+
catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested)
42+
{
43+
throw new TimeoutException($"Authentication timed out after {_timeout.TotalSeconds} seconds.");
44+
}
45+
}
46+
}

0 commit comments

Comments
 (0)