Skip to content

Commit ec25187

Browse files
committed
Functionality consolidation
1 parent 70146dd commit ec25187

File tree

2 files changed

+57
-69
lines changed

2 files changed

+57
-69
lines changed

src/ModelContextProtocol/Auth/OAuthAuthenticationService.cs

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,37 @@ public async Task<OAuthToken> HandleAuthenticationAsync(
116116
return tokenResponse;
117117
}
118118

119+
/// <summary>
120+
/// Handles the exchange of an authorization code for an OAuth token.
121+
/// </summary>
122+
/// <param name="tokenEndpoint">The token endpoint URI.</param>
123+
/// <param name="clientId">The client ID.</param>
124+
/// <param name="clientSecret">The client secret, if any.</param>
125+
/// <param name="redirectUri">The redirect URI used in the authorization request.</param>
126+
/// <param name="authorizationCode">The authorization code received from the authorization server.</param>
127+
/// <param name="codeVerifier">The PKCE code verifier.</param>
128+
/// <param name="cancellationToken">A cancellation token to cancel the operation.</param>
129+
/// <returns>The OAuth token response.</returns>
130+
public async Task<OAuthToken> HandleAuthorizationCodeAsync(
131+
Uri tokenEndpoint,
132+
string clientId,
133+
string? clientSecret,
134+
Uri redirectUri,
135+
string authorizationCode,
136+
string codeVerifier,
137+
CancellationToken cancellationToken = default)
138+
{
139+
// Simply call our private implementation
140+
return await ExchangeAuthorizationCodeForTokenAsync(
141+
tokenEndpoint,
142+
clientId,
143+
clientSecret,
144+
redirectUri,
145+
authorizationCode,
146+
codeVerifier,
147+
cancellationToken);
148+
}
149+
119150
private Uri? ExtractResourceMetadataUri(string wwwAuthenticateHeader)
120151
{
121152
if (string.IsNullOrEmpty(wwwAuthenticateHeader))
@@ -356,14 +387,25 @@ private string GenerateRandomString(int length)
356387
.Substring(0, length);
357388
}
358389

359-
// This method would be used in a real implementation after receiving the authorization code
390+
/// <summary>
391+
/// Exchanges an authorization code for an OAuth token.
392+
/// </summary>
393+
/// <param name="tokenEndpoint">The token endpoint URI.</param>
394+
/// <param name="clientId">The client ID.</param>
395+
/// <param name="clientSecret">The client secret, if any.</param>
396+
/// <param name="redirectUri">The redirect URI used in the authorization request.</param>
397+
/// <param name="authorizationCode">The authorization code received from the authorization server.</param>
398+
/// <param name="codeVerifier">The PKCE code verifier.</param>
399+
/// <param name="cancellationToken">A cancellation token to cancel the operation.</param>
400+
/// <returns>The OAuth token response.</returns>
360401
private async Task<OAuthToken> ExchangeAuthorizationCodeForTokenAsync(
361402
Uri tokenEndpoint,
362403
string clientId,
363404
string? clientSecret,
364405
Uri redirectUri,
365406
string authorizationCode,
366-
string codeVerifier)
407+
string codeVerifier,
408+
CancellationToken cancellationToken = default)
367409
{
368410
var tokenRequest = new Dictionary<string, string>
369411
{
@@ -381,18 +423,21 @@ private async Task<OAuthToken> ExchangeAuthorizationCodeForTokenAsync(
381423
{
382424
// Add client authentication if secret is available
383425
var authValue = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{clientId}:{clientSecret}"));
384-
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authValue);
385-
response = await _httpClient.PostAsync(tokenEndpoint, requestContent);
386-
_httpClient.DefaultRequestHeaders.Authorization = null;
426+
using var request = new HttpRequestMessage(HttpMethod.Post, tokenEndpoint)
427+
{
428+
Content = requestContent
429+
};
430+
request.Headers.Authorization = new AuthenticationHeaderValue("Basic", authValue);
431+
response = await _httpClient.SendAsync(request, cancellationToken);
387432
}
388433
else
389434
{
390-
response = await _httpClient.PostAsync(tokenEndpoint, requestContent);
435+
response = await _httpClient.PostAsync(tokenEndpoint, requestContent, cancellationToken);
391436
}
392437

393438
response.EnsureSuccessStatusCode();
394439

395-
var json = await response.Content.ReadAsStringAsync();
440+
var json = await response.Content.ReadAsStringAsync(cancellationToken);
396441
var tokenResponse = JsonSerializer.Deserialize(json, McpJsonUtilities.DefaultOptions.GetTypeInfo<OAuthToken>());
397442
if (tokenResponse == null)
398443
{

src/ModelContextProtocol/Auth/OAuthAuthorizationHelpers.cs

Lines changed: 5 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -163,66 +163,6 @@ public static Func<Uri, Task<string>> CreateHttpListenerCallback(
163163
};
164164
}
165165

166-
/// <summary>
167-
/// Exchanges an authorization code for an OAuth token.
168-
/// </summary>
169-
/// <param name="tokenEndpoint">The token endpoint URI.</param>
170-
/// <param name="clientId">The client ID.</param>
171-
/// <param name="clientSecret">The client secret, if any.</param>
172-
/// <param name="redirectUri">The redirect URI used in the authorization request.</param>
173-
/// <param name="authorizationCode">The authorization code received from the authorization server.</param>
174-
/// <param name="codeVerifier">The PKCE code verifier.</param>
175-
/// <param name="cancellationToken">A cancellation token to cancel the operation.</param>
176-
/// <returns>The OAuth token response.</returns>
177-
public static async Task<OAuthToken> ExchangeAuthorizationCodeForTokenAsync(
178-
Uri tokenEndpoint,
179-
string clientId,
180-
string? clientSecret,
181-
Uri redirectUri,
182-
string authorizationCode,
183-
string codeVerifier,
184-
CancellationToken cancellationToken = default)
185-
{
186-
var tokenRequest = new Dictionary<string, string>
187-
{
188-
["grant_type"] = "authorization_code",
189-
["code"] = authorizationCode,
190-
["redirect_uri"] = redirectUri.ToString(),
191-
["client_id"] = clientId,
192-
["code_verifier"] = codeVerifier
193-
};
194-
195-
var requestContent = new FormUrlEncodedContent(tokenRequest);
196-
197-
HttpResponseMessage response;
198-
if (!string.IsNullOrEmpty(clientSecret))
199-
{
200-
// Add client authentication if secret is available
201-
var authValue = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{clientId}:{clientSecret}"));
202-
using var request = new HttpRequestMessage(HttpMethod.Post, tokenEndpoint)
203-
{
204-
Content = requestContent
205-
};
206-
request.Headers.Authorization = new AuthenticationHeaderValue("Basic", authValue);
207-
response = await _httpClient.SendAsync(request, cancellationToken);
208-
}
209-
else
210-
{
211-
response = await _httpClient.PostAsync(tokenEndpoint, requestContent, cancellationToken);
212-
}
213-
214-
response.EnsureSuccessStatusCode();
215-
216-
var json = await response.Content.ReadAsStringAsync(cancellationToken);
217-
var tokenResponse = JsonSerializer.Deserialize(json, McpJsonUtilities.DefaultOptions.GetTypeInfo<OAuthToken>());
218-
if (tokenResponse == null)
219-
{
220-
throw new InvalidOperationException("Failed to parse token response.");
221-
}
222-
223-
return tokenResponse;
224-
}
225-
226166
/// <summary>
227167
/// Creates a complete OAuth authorization code flow handler that automatically exchanges the code for a token.
228168
/// </summary>
@@ -249,13 +189,16 @@ public static Func<Uri, Task<OAuthToken>> CreateCompleteOAuthFlowHandler(
249189
{
250190
var codeHandler = CreateHttpListenerCallback(openBrowser, hostname, listenPort, redirectPath);
251191

192+
// Create an OAuth authentication service to handle token exchange
193+
var authService = new OAuthAuthenticationService();
194+
252195
return async (authorizationUri) =>
253196
{
254197
// First get the authorization code
255198
string authorizationCode = await codeHandler(authorizationUri);
256199

257-
// Then exchange it for a token
258-
return await ExchangeAuthorizationCodeForTokenAsync(
200+
// Let the authentication service handle the token exchange
201+
return await authService.HandleAuthorizationCodeAsync(
259202
tokenEndpoint,
260203
clientId,
261204
clientSecret,

0 commit comments

Comments
 (0)