Skip to content

Commit 11e724e

Browse files
Added ExchangeCodeAsync method for Untappd (#530)
* Added ExchangeCodeAsync Method. Fix for the JSON structure. Changed bundle.json for the tests. * Update src/AspNet.Security.OAuth.Untappd/UntappdAuthenticationHandler.cs Newer initializer syntax as per suggestion Co-authored-by: Martin Costello <[email protected]> * Update src/AspNet.Security.OAuth.Untappd/UntappdAuthenticationHandler.cs add using as per suggestion Co-authored-by: Martin Costello <[email protected]> * Update src/AspNet.Security.OAuth.Untappd/UntappdAuthenticationHandler.cs add using as per suggestion Co-authored-by: Martin Costello <[email protected]> * Changed ParseQueryString to QueryHelpers * Adapted to failure handling pattern * indentation * Fixed test * Apply suggestions from code review Minor formatting changes. Co-authored-by: Martin Costello <[email protected]>
1 parent 9e1fef4 commit 11e724e

File tree

2 files changed

+83
-12
lines changed

2 files changed

+83
-12
lines changed

src/AspNet.Security.OAuth.Untappd/UntappdAuthenticationHandler.cs

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,23 @@
1-
/*
1+
/*
22
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
33
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
44
* for more information concerning the license and the contributors participating to this project.
55
*/
66

7+
using System;
8+
using System.Collections.Generic;
79
using System.Net.Http;
810
using System.Net.Http.Headers;
911
using System.Security.Claims;
12+
using System.Text;
1013
using System.Text.Encodings.Web;
1114
using System.Text.Json;
1215
using System.Threading.Tasks;
16+
using System.Web;
1317
using JetBrains.Annotations;
1418
using Microsoft.AspNetCore.Authentication;
1519
using Microsoft.AspNetCore.Authentication.OAuth;
20+
using Microsoft.AspNetCore.WebUtilities;
1621
using Microsoft.Extensions.Logging;
1722
using Microsoft.Extensions.Options;
1823

@@ -29,6 +34,58 @@ public UntappdAuthenticationHandler(
2934
{
3035
}
3136

37+
protected override async Task<OAuthTokenResponse> ExchangeCodeAsync([NotNull] OAuthCodeExchangeContext context)
38+
{
39+
var tokenRequestParameters = new Dictionary<string, string>()
40+
{
41+
["client_id"] = Options.ClientId,
42+
["redirect_uri"] = context.RedirectUri,
43+
["client_secret"] = Options.ClientSecret,
44+
["code"] = context.Code,
45+
["grant_type"] = "authorization_code",
46+
};
47+
48+
// PKCE https://tools.ietf.org/html/rfc7636#section-4.5, see BuildChallengeUrl
49+
if (context.Properties.Items.TryGetValue(OAuthConstants.CodeVerifierKey, out var codeVerifier))
50+
{
51+
tokenRequestParameters.Add(OAuthConstants.CodeVerifierKey, codeVerifier!);
52+
context.Properties.Items.Remove(OAuthConstants.CodeVerifierKey);
53+
}
54+
55+
using var requestContent = new FormUrlEncodedContent(tokenRequestParameters!);
56+
57+
string address = QueryHelpers.AddQueryString(Options.TokenEndpoint,
58+
new Dictionary<string, string?>
59+
{
60+
["client_id"] = Options.ClientId,
61+
["redirect_uri"] = context.RedirectUri,
62+
["client_secret"] = Options.ClientSecret,
63+
["code"] = context.Code
64+
});
65+
66+
using var requestMessage = new HttpRequestMessage(HttpMethod.Get, address);
67+
requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
68+
requestMessage.Content = requestContent;
69+
requestMessage.Version = Backchannel.DefaultRequestVersion;
70+
71+
using var response = await Backchannel.SendAsync(requestMessage, Context.RequestAborted);
72+
if (response.IsSuccessStatusCode)
73+
{
74+
var payload = JsonDocument.Parse(await response.Content.ReadAsStringAsync(Context.RequestAborted));
75+
return OAuthTokenResponse.Success(payload);
76+
}
77+
else
78+
{
79+
Logger.LogWarning("An error occurred while exchanging token codes. " +
80+
"the remote server returned a {Status} response with the following payload: {Headers} {Body}.",
81+
/* Status: */ response.StatusCode,
82+
/* Headers: */ response.Headers.ToString(),
83+
/* Body: */ await response.Content.ReadAsStringAsync(Context.RequestAborted));
84+
85+
throw new HttpRequestException("An error occurred while exchanging token codes.");
86+
}
87+
}
88+
3289
protected override async Task<AuthenticationTicket> CreateTicketAsync(
3390
[NotNull] ClaimsIdentity identity,
3491
[NotNull] AuthenticationProperties properties,
@@ -54,7 +111,8 @@ protected override async Task<AuthenticationTicket> CreateTicketAsync(
54111

55112
var principal = new ClaimsPrincipal(identity);
56113
var context = new OAuthCreatingTicketContext(principal, properties, Context, Scheme, Options, Backchannel, tokens, payload.RootElement);
57-
context.RunClaimActions(payload.RootElement.GetProperty("user"));
114+
115+
context.RunClaimActions(payload.RootElement.GetProperty("response").GetProperty("user"));
58116

59117
await Options.Events.CreatingTicket(context);
60118
return new AuthenticationTicket(context.Principal!, context.Properties, Scheme.Name);

test/AspNet.Security.OAuth.Providers.Tests/Untappd/bundle.json

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,33 @@
1212
"expires_in": "300"
1313
}
1414
},
15+
{
16+
"uri": "https://untappd.com/oauth/authorize?client_id=my-client-id&redirect_uri=http%3A%2F%2Flocalhost%2Fsignin-untappd&client_secret=my-client-secret&code=a6ed8e7f-471f-44f1-903b-65946475f351",
17+
"method": "GET",
18+
"contentFormat": "json",
19+
"contentJson": {
20+
"access_token": "secret-access-token",
21+
"token_type": "access",
22+
"refresh_token": "secret-refresh-token",
23+
"expires_in": "300"
24+
}
25+
},
1526
{
1627
"uri": "https://api.untappd.com/v4/user/info",
1728
"contentFormat": "json",
1829
"contentJson": {
19-
"user": {
20-
"id": "my-id",
21-
"first_name": "John",
22-
"last_name": "Smith",
23-
"user_name": "John Smith",
24-
"email": "[email protected]",
25-
"url": "https://untappd.local/JohnSmith",
26-
"user_avatar": "https://untappd.local/john-smith.png"
30+
"response": {
31+
"user": {
32+
"id": "my-id",
33+
"first_name": "John",
34+
"last_name": "Smith",
35+
"user_name": "John Smith",
36+
"email": "[email protected]",
37+
"url": "https://untappd.local/JohnSmith",
38+
"user_avatar": "https://untappd.local/john-smith.png"
39+
}
2740
}
28-
}
29-
}
41+
}
42+
}
3043
]
3144
}

0 commit comments

Comments
 (0)