Skip to content

Commit cd44a42

Browse files
Fix Notion code exchange (#564)
* Fix Notion code exchange * Update src/AspNet.Security.OAuth.Notion/NotionAuthenticationHandler.cs Co-authored-by: Martin Costello <[email protected]> * Update src/AspNet.Security.OAuth.Notion/NotionAuthenticationHandler.cs Co-authored-by: Martin Costello <[email protected]> * Update src/AspNet.Security.OAuth.Notion/NotionAuthenticationHandler.cs Co-authored-by: Martin Costello <[email protected]> * Update src/AspNet.Security.OAuth.Notion/NotionAuthenticationHandler.cs Co-authored-by: Martin Costello <[email protected]> * Update src/AspNet.Security.OAuth.Notion/NotionAuthenticationHandler.cs Co-authored-by: Martin Costello <[email protected]> * Update src/AspNet.Security.OAuth.Notion/NotionAuthenticationHandler.cs Co-authored-by: Martin Costello <[email protected]> * Update src/AspNet.Security.OAuth.Notion/NotionAuthenticationHandler.cs Co-authored-by: Martin Costello <[email protected]> * Update src/AspNet.Security.OAuth.Notion/NotionAuthenticationHandler.cs Co-authored-by: Martin Costello <[email protected]> Co-authored-by: Martin Costello <[email protected]>
1 parent 17b8242 commit cd44a42

File tree

1 file changed

+56
-0
lines changed

1 file changed

+56
-0
lines changed

src/AspNet.Security.OAuth.Notion/NotionAuthenticationHandler.cs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,14 @@
44
* for more information concerning the license and the contributors participating to this project.
55
*/
66

7+
using System;
8+
using System.Collections.Generic;
9+
using System.Net.Http;
10+
using System.Net.Http.Headers;
711
using System.Security.Claims;
12+
using System.Text;
813
using System.Text.Encodings.Web;
14+
using System.Text.Json;
915
using System.Threading.Tasks;
1016
using JetBrains.Annotations;
1117
using Microsoft.AspNetCore.Authentication;
@@ -26,6 +32,47 @@ public NotionAuthenticationHandler(
2632
{
2733
}
2834

35+
protected override async Task<OAuthTokenResponse> ExchangeCodeAsync(OAuthCodeExchangeContext context)
36+
{
37+
var tokenRequestParameters = new Dictionary<string, string>()
38+
{
39+
["client_id"] = Options.ClientId,
40+
["redirect_uri"] = context.RedirectUri,
41+
["client_secret"] = Options.ClientSecret,
42+
["code"] = context.Code,
43+
["grant_type"] = "authorization_code",
44+
};
45+
46+
// PKCE https://tools.ietf.org/html/rfc7636#section-4.5, see BuildChallengeUrl
47+
if (context.Properties.Items.TryGetValue(OAuthConstants.CodeVerifierKey, out var codeVerifier) &&
48+
!string.IsNullOrEmpty(codeVerifier))
49+
{
50+
tokenRequestParameters[OAuthConstants.CodeVerifierKey] = codeVerifier;
51+
context.Properties.Items.Remove(OAuthConstants.CodeVerifierKey);
52+
}
53+
54+
using var requestContent = new FormUrlEncodedContent(tokenRequestParameters!);
55+
56+
using var requestMessage = new HttpRequestMessage(HttpMethod.Post, Options.TokenEndpoint);
57+
requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
58+
59+
byte[] byteArray = Encoding.ASCII.GetBytes(Options.ClientId + ":" + Options.ClientSecret);
60+
requestMessage.Headers.Authorization =
61+
new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
62+
requestMessage.Content = requestContent;
63+
requestMessage.Version = Backchannel.DefaultRequestVersion;
64+
65+
using var response = await Backchannel.SendAsync(requestMessage, Context.RequestAborted);
66+
if (response.IsSuccessStatusCode)
67+
{
68+
var payload = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
69+
return OAuthTokenResponse.Success(payload);
70+
}
71+
72+
var error = "OAuth token endpoint failure: " + await DisplayAsync(response);
73+
return OAuthTokenResponse.Failed(new Exception(error));
74+
}
75+
2976
protected override async Task<AuthenticationTicket> CreateTicketAsync(
3077
[NotNull] ClaimsIdentity identity,
3178
[NotNull] AuthenticationProperties properties,
@@ -46,5 +93,14 @@ protected override async Task<AuthenticationTicket> CreateTicketAsync(
4693
await Options.Events.CreatingTicket(context);
4794
return new AuthenticationTicket(context.Principal!, context.Properties, Scheme.Name);
4895
}
96+
97+
private static async Task<string> DisplayAsync(HttpResponseMessage response)
98+
{
99+
var output = new StringBuilder();
100+
output.Append("Status: ").Append(response.StatusCode).Append(';');
101+
output.Append("Headers: ").Append(response.Headers).Append(';');
102+
output.Append("Body: ").Append(await response.Content.ReadAsStringAsync()).Append(';');
103+
return output.ToString();
104+
}
49105
}
50106
}

0 commit comments

Comments
 (0)