Skip to content

Commit a75b8f9

Browse files
authored
Migrate to Autodesk v2 (#764)
Migrate to v2 of the Autodesk API.
1 parent b5c152c commit a75b8f9

File tree

5 files changed

+69
-20
lines changed

5 files changed

+69
-20
lines changed

src/AspNet.Security.OAuth.Autodesk/AutodeskAuthenticationDefaults.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,15 @@ public static class AutodeskAuthenticationDefaults
3434
/// <summary>
3535
/// Default value for <see cref="OAuthOptions.AuthorizationEndpoint"/>.
3636
/// </summary>
37-
public static readonly string AuthorizationEndpoint = "https://developer.api.autodesk.com/authentication/v1/authorize";
37+
public static readonly string AuthorizationEndpoint = "https://developer.api.autodesk.com/authentication/v2/authorize";
3838

3939
/// <summary>
4040
/// Default value for <see cref="OAuthOptions.TokenEndpoint"/>.
4141
/// </summary>
42-
public static readonly string TokenEndpoint = "https://developer.api.autodesk.com/authentication/v1/gettoken";
42+
public static readonly string TokenEndpoint = "https://developer.api.autodesk.com/authentication/v2/token";
4343

4444
/// <summary>
4545
/// Default value for <see cref="OAuthOptions.UserInformationEndpoint"/>.
4646
/// </summary>
47-
public static readonly string UserInformationEndpoint = "https://developer.api.autodesk.com/userprofile/v1/users/@me";
47+
public static readonly string UserInformationEndpoint = "https://api.userprofile.autodesk.com/userinfo";
4848
}

src/AspNet.Security.OAuth.Autodesk/AutodeskAuthenticationHandler.cs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
using System.Net.Http.Headers;
88
using System.Security.Claims;
9+
using System.Text;
910
using System.Text.Encodings.Web;
1011
using System.Text.Json;
1112
using Microsoft.Extensions.Logging;
@@ -50,6 +51,41 @@ protected override async Task<AuthenticationTicket> CreateTicketAsync(
5051
return new AuthenticationTicket(context.Principal!, context.Properties, Scheme.Name);
5152
}
5253

54+
protected override async Task<OAuthTokenResponse> ExchangeCodeAsync([NotNull] OAuthCodeExchangeContext context)
55+
{
56+
var tokenRequestParameters = new Dictionary<string, string>
57+
{
58+
["redirect_uri"] = context.RedirectUri,
59+
["code"] = context.Code,
60+
["grant_type"] = "authorization_code"
61+
};
62+
63+
// PKCE https://tools.ietf.org/html/rfc7636#section-4.5, see BuildChallengeUrl
64+
if (context.Properties.Items.TryGetValue(OAuthConstants.CodeVerifierKey, out var codeVerifier))
65+
{
66+
tokenRequestParameters[OAuthConstants.CodeVerifierKey] = codeVerifier!;
67+
context.Properties.Items.Remove(OAuthConstants.CodeVerifierKey);
68+
}
69+
70+
using var requestContent = new FormUrlEncodedContent(tokenRequestParameters!);
71+
using var requestMessage = new HttpRequestMessage(HttpMethod.Post, Options.TokenEndpoint);
72+
requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
73+
var credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes(
74+
$"{Options.ClientId}:{Options.ClientSecret}"));
75+
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Basic", credentials);
76+
requestMessage.Content = requestContent;
77+
requestMessage.Version = Backchannel.DefaultRequestVersion;
78+
using var response = await Backchannel.SendAsync(requestMessage, Context.RequestAborted);
79+
if (!response.IsSuccessStatusCode)
80+
{
81+
await Log.ExchangeCodeAsync(Logger, response, Context.RequestAborted);
82+
return OAuthTokenResponse.Failed(new Exception("An error occurred while retrieving an access token."));
83+
}
84+
85+
var body = await response.Content.ReadAsStringAsync(Context.RequestAborted);
86+
return OAuthTokenResponse.Success(JsonDocument.Parse(body));
87+
}
88+
5389
private static partial class Log
5490
{
5591
internal static async Task UserProfileErrorAsync(ILogger logger, HttpResponseMessage response, CancellationToken cancellationToken)
@@ -67,5 +103,21 @@ private static partial void UserProfileError(
67103
System.Net.HttpStatusCode status,
68104
string headers,
69105
string body);
106+
107+
internal static async Task ExchangeCodeAsync(ILogger logger, HttpResponseMessage response, CancellationToken cancellationToken)
108+
{
109+
ExchangeCodeAsync(
110+
logger,
111+
response.StatusCode,
112+
response.Headers.ToString(),
113+
await response.Content.ReadAsStringAsync(cancellationToken));
114+
}
115+
116+
[LoggerMessage(2, LogLevel.Error, "An error occurred while retrieving an access token: the remote server returned a {Status} response with the following payload: {Headers} {Body}.")]
117+
static partial void ExchangeCodeAsync(
118+
ILogger logger,
119+
System.Net.HttpStatusCode status,
120+
string headers,
121+
string body);
70122
}
71123
}

src/AspNet.Security.OAuth.Autodesk/AutodeskAuthenticationOptions.cs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,11 @@ public AutodeskAuthenticationOptions()
2525

2626
Scope.Add("user-profile:read");
2727

28-
ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "userId");
29-
ClaimActions.MapJsonKey(ClaimTypes.Name, "userName");
30-
ClaimActions.MapJsonKey(ClaimTypes.GivenName, "firstName");
31-
ClaimActions.MapJsonKey(ClaimTypes.Surname, "lastName");
32-
ClaimActions.MapJsonKey(ClaimTypes.Email, "emailId");
33-
ClaimActions.MapJsonKey(Claims.EmailVerified, "emailVerified");
34-
ClaimActions.MapJsonKey(Claims.TwoFactorEnabled, "2FaEnabled");
28+
ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "sub");
29+
ClaimActions.MapJsonKey(ClaimTypes.Name, "preferred_username");
30+
ClaimActions.MapJsonKey(ClaimTypes.GivenName, "given_name");
31+
ClaimActions.MapJsonKey(ClaimTypes.Surname, "family_name");
32+
ClaimActions.MapJsonKey(ClaimTypes.Email, "email");
33+
ClaimActions.MapJsonKey(Claims.EmailVerified, "email_verified");
3534
}
3635
}

test/AspNet.Security.OAuth.Providers.Tests/Autodesk/AutodeskTests.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ protected internal override void RegisterAuthentication(AuthenticationBuilder bu
2727
[InlineData(ClaimTypes.GivenName, "John")]
2828
[InlineData(ClaimTypes.Surname, "Smith")]
2929
[InlineData("urn:autodesk:emailverified", "True")]
30-
[InlineData("urn:autodesk:twofactorenabled", "False")]
3130
public async Task Can_Sign_In_Using_Autodesk(string claimType, string claimValue)
3231
{
3332
// Arrange

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

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"$schema": "https://raw.githubusercontent.com/justeat/httpclient-interception/master/src/HttpClientInterception/Bundles/http-request-bundle-schema.json",
33
"items": [
44
{
5-
"uri": "https://developer.api.autodesk.com/authentication/v1/gettoken",
5+
"uri": "https://developer.api.autodesk.com/authentication/v2/token",
66
"method": "POST",
77
"contentFormat": "json",
88
"contentJson": {
@@ -13,16 +13,15 @@
1313
}
1414
},
1515
{
16-
"uri": "https://developer.api.autodesk.com/userprofile/v1/users/@me",
16+
"uri": "https://api.userprofile.autodesk.com/userinfo",
1717
"contentFormat": "json",
1818
"contentJson": {
19-
"userId": "my-id",
20-
"userName": "John Smith",
21-
"firstName": "John",
22-
"lastName": "Smith",
23-
"emailId": "[email protected]",
24-
"emailVerified": true,
25-
"2FaEnabled": false
19+
"sub": "my-id",
20+
"preferred_username": "John Smith",
21+
"given_name": "John",
22+
"family_name": "Smith",
23+
"email": "[email protected]",
24+
"email_verified": true
2625
}
2726
}
2827
]

0 commit comments

Comments
 (0)