Skip to content

Commit 405db57

Browse files
committed
Organize things better
1 parent a3926ee commit 405db57

14 files changed

+80
-63
lines changed

src/ModelContextProtocol.AspNetCore/Auth/ResourceMetadataService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
using Microsoft.AspNetCore.Http;
2-
using ModelContextProtocol.Auth;
2+
using ModelContextProtocol.Auth.Types;
33
using ModelContextProtocol.Utils.Json;
44

55
namespace ModelContextProtocol.AspNetCore.Auth;

src/ModelContextProtocol.AspNetCore/HttpMcpServerBuilderExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using Microsoft.Extensions.DependencyInjection.Extensions;
22
using ModelContextProtocol.AspNetCore;
33
using ModelContextProtocol.AspNetCore.Auth;
4-
using ModelContextProtocol.Auth;
4+
using ModelContextProtocol.Auth.Types;
55
using ModelContextProtocol.Server;
66

77
namespace Microsoft.Extensions.DependencyInjection;

src/ModelContextProtocol/Auth/McpClientExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Net.Http.Headers;
22
using System.Collections.Concurrent;
3+
using ModelContextProtocol.Auth.Types;
34

45
namespace ModelContextProtocol.Auth;
56

src/ModelContextProtocol/Auth/OAuthAuthenticationService.cs

Lines changed: 8 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Security.Cryptography;
44
using System.Text;
55
using System.Text.Json;
6+
using ModelContextProtocol.Auth.Types;
67
using ModelContextProtocol.Utils.Json;
78

89
namespace ModelContextProtocol.Auth;
@@ -116,37 +117,6 @@ public async Task<OAuthToken> HandleAuthenticationAsync(
116117
return tokenResponse;
117118
}
118119

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-
150120
private Uri? ExtractResourceMetadataUri(string wwwAuthenticateHeader)
151121
{
152122
if (string.IsNullOrEmpty(wwwAuthenticateHeader))
@@ -387,25 +357,14 @@ private string GenerateRandomString(int length)
387357
.Substring(0, length);
388358
}
389359

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>
360+
// This method would be used in a real implementation after receiving the authorization code
401361
private async Task<OAuthToken> ExchangeAuthorizationCodeForTokenAsync(
402362
Uri tokenEndpoint,
403363
string clientId,
404364
string? clientSecret,
405365
Uri redirectUri,
406366
string authorizationCode,
407-
string codeVerifier,
408-
CancellationToken cancellationToken = default)
367+
string codeVerifier)
409368
{
410369
var tokenRequest = new Dictionary<string, string>
411370
{
@@ -423,21 +382,18 @@ private async Task<OAuthToken> ExchangeAuthorizationCodeForTokenAsync(
423382
{
424383
// Add client authentication if secret is available
425384
var authValue = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{clientId}:{clientSecret}"));
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);
385+
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authValue);
386+
response = await _httpClient.PostAsync(tokenEndpoint, requestContent);
387+
_httpClient.DefaultRequestHeaders.Authorization = null;
432388
}
433389
else
434390
{
435-
response = await _httpClient.PostAsync(tokenEndpoint, requestContent, cancellationToken);
391+
response = await _httpClient.PostAsync(tokenEndpoint, requestContent);
436392
}
437393

438394
response.EnsureSuccessStatusCode();
439395

440-
var json = await response.Content.ReadAsStringAsync(cancellationToken);
396+
var json = await response.Content.ReadAsStringAsync();
441397
var tokenResponse = JsonSerializer.Deserialize(json, McpJsonUtilities.DefaultOptions.GetTypeInfo<OAuthToken>());
442398
if (tokenResponse == null)
443399
{

src/ModelContextProtocol/Auth/OAuthAuthorizationHelpers.cs

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Text.Json;
88
using System.Threading;
99
using System.Threading.Tasks;
10+
using ModelContextProtocol.Auth.Types;
1011
using ModelContextProtocol.Utils.Json;
1112

1213
namespace ModelContextProtocol.Auth;
@@ -163,6 +164,66 @@ public static Func<Uri, Task<string>> CreateHttpListenerCallback(
163164
};
164165
}
165166

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

192-
// Create an OAuth authentication service to handle token exchange
193-
var authService = new OAuthAuthenticationService();
194-
195253
return async (authorizationUri) =>
196254
{
197255
// First get the authorization code
198256
string authorizationCode = await codeHandler(authorizationUri);
199257

200-
// Let the authentication service handle the token exchange
201-
return await authService.HandleAuthorizationCodeAsync(
258+
// Then exchange it for a token
259+
return await ExchangeAuthorizationCodeForTokenAsync(
202260
tokenEndpoint,
203261
clientId,
204262
clientSecret,

src/ModelContextProtocol/Auth/OAuthDelegatingHandler.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using ModelContextProtocol.Auth.Types;
12
using System.Net;
23
using System.Net.Http.Headers;
34

src/ModelContextProtocol/Auth/AuthorizationCodeOptions.cs renamed to src/ModelContextProtocol/Auth/Types/AuthorizationCodeOptions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace ModelContextProtocol.Auth;
1+
namespace ModelContextProtocol.Auth.Types;
22

33
/// <summary>
44
/// Configuration options for the authorization code flow.

src/ModelContextProtocol/Auth/AuthorizationConfig.cs renamed to src/ModelContextProtocol/Auth/Types/AuthorizationConfig.cs

File renamed without changes.

src/ModelContextProtocol/Auth/AuthorizationServerMetadata.cs renamed to src/ModelContextProtocol/Auth/Types/AuthorizationServerMetadata.cs

File renamed without changes.

src/ModelContextProtocol/Auth/ClientRegistrationRequest.cs renamed to src/ModelContextProtocol/Auth/Types/ClientRegistrationRequest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using System.Text.Json.Serialization;
22

3-
namespace ModelContextProtocol.Auth;
3+
namespace ModelContextProtocol.Auth.Types;
44

55
/// <summary>
66
/// Represents the client registration request metadata.

0 commit comments

Comments
 (0)