Skip to content

Commit

Permalink
Migrate to Autodesk v2 (#764)
Browse files Browse the repository at this point in the history
Migrate to v2 of the Autodesk API.
  • Loading branch information
EMostafaAli authored Aug 7, 2023
1 parent b5c152c commit a75b8f9
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,15 @@ public static class AutodeskAuthenticationDefaults
/// <summary>
/// Default value for <see cref="OAuthOptions.AuthorizationEndpoint"/>.
/// </summary>
public static readonly string AuthorizationEndpoint = "https://developer.api.autodesk.com/authentication/v1/authorize";
public static readonly string AuthorizationEndpoint = "https://developer.api.autodesk.com/authentication/v2/authorize";

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

/// <summary>
/// Default value for <see cref="OAuthOptions.UserInformationEndpoint"/>.
/// </summary>
public static readonly string UserInformationEndpoint = "https://developer.api.autodesk.com/userprofile/v1/users/@me";
public static readonly string UserInformationEndpoint = "https://api.userprofile.autodesk.com/userinfo";
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

using System.Net.Http.Headers;
using System.Security.Claims;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
using Microsoft.Extensions.Logging;
Expand Down Expand Up @@ -50,6 +51,41 @@ protected override async Task<AuthenticationTicket> CreateTicketAsync(
return new AuthenticationTicket(context.Principal!, context.Properties, Scheme.Name);
}

protected override async Task<OAuthTokenResponse> ExchangeCodeAsync([NotNull] OAuthCodeExchangeContext context)
{
var tokenRequestParameters = new Dictionary<string, string>
{
["redirect_uri"] = context.RedirectUri,
["code"] = context.Code,
["grant_type"] = "authorization_code"
};

// PKCE https://tools.ietf.org/html/rfc7636#section-4.5, see BuildChallengeUrl
if (context.Properties.Items.TryGetValue(OAuthConstants.CodeVerifierKey, out var codeVerifier))
{
tokenRequestParameters[OAuthConstants.CodeVerifierKey] = codeVerifier!;
context.Properties.Items.Remove(OAuthConstants.CodeVerifierKey);
}

using var requestContent = new FormUrlEncodedContent(tokenRequestParameters!);
using var requestMessage = new HttpRequestMessage(HttpMethod.Post, Options.TokenEndpoint);
requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes(
$"{Options.ClientId}:{Options.ClientSecret}"));
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Basic", credentials);
requestMessage.Content = requestContent;
requestMessage.Version = Backchannel.DefaultRequestVersion;
using var response = await Backchannel.SendAsync(requestMessage, Context.RequestAborted);
if (!response.IsSuccessStatusCode)
{
await Log.ExchangeCodeAsync(Logger, response, Context.RequestAborted);
return OAuthTokenResponse.Failed(new Exception("An error occurred while retrieving an access token."));
}

var body = await response.Content.ReadAsStringAsync(Context.RequestAborted);
return OAuthTokenResponse.Success(JsonDocument.Parse(body));
}

private static partial class Log
{
internal static async Task UserProfileErrorAsync(ILogger logger, HttpResponseMessage response, CancellationToken cancellationToken)
Expand All @@ -67,5 +103,21 @@ private static partial void UserProfileError(
System.Net.HttpStatusCode status,
string headers,
string body);

internal static async Task ExchangeCodeAsync(ILogger logger, HttpResponseMessage response, CancellationToken cancellationToken)
{
ExchangeCodeAsync(
logger,
response.StatusCode,
response.Headers.ToString(),
await response.Content.ReadAsStringAsync(cancellationToken));
}

[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}.")]
static partial void ExchangeCodeAsync(
ILogger logger,
System.Net.HttpStatusCode status,
string headers,
string body);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,11 @@ public AutodeskAuthenticationOptions()

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

ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "userId");
ClaimActions.MapJsonKey(ClaimTypes.Name, "userName");
ClaimActions.MapJsonKey(ClaimTypes.GivenName, "firstName");
ClaimActions.MapJsonKey(ClaimTypes.Surname, "lastName");
ClaimActions.MapJsonKey(ClaimTypes.Email, "emailId");
ClaimActions.MapJsonKey(Claims.EmailVerified, "emailVerified");
ClaimActions.MapJsonKey(Claims.TwoFactorEnabled, "2FaEnabled");
ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "sub");
ClaimActions.MapJsonKey(ClaimTypes.Name, "preferred_username");
ClaimActions.MapJsonKey(ClaimTypes.GivenName, "given_name");
ClaimActions.MapJsonKey(ClaimTypes.Surname, "family_name");
ClaimActions.MapJsonKey(ClaimTypes.Email, "email");
ClaimActions.MapJsonKey(Claims.EmailVerified, "email_verified");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ protected internal override void RegisterAuthentication(AuthenticationBuilder bu
[InlineData(ClaimTypes.GivenName, "John")]
[InlineData(ClaimTypes.Surname, "Smith")]
[InlineData("urn:autodesk:emailverified", "True")]
[InlineData("urn:autodesk:twofactorenabled", "False")]
public async Task Can_Sign_In_Using_Autodesk(string claimType, string claimValue)
{
// Arrange
Expand Down
17 changes: 8 additions & 9 deletions test/AspNet.Security.OAuth.Providers.Tests/Autodesk/bundle.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "https://raw.githubusercontent.com/justeat/httpclient-interception/master/src/HttpClientInterception/Bundles/http-request-bundle-schema.json",
"items": [
{
"uri": "https://developer.api.autodesk.com/authentication/v1/gettoken",
"uri": "https://developer.api.autodesk.com/authentication/v2/token",
"method": "POST",
"contentFormat": "json",
"contentJson": {
Expand All @@ -13,16 +13,15 @@
}
},
{
"uri": "https://developer.api.autodesk.com/userprofile/v1/users/@me",
"uri": "https://api.userprofile.autodesk.com/userinfo",
"contentFormat": "json",
"contentJson": {
"userId": "my-id",
"userName": "John Smith",
"firstName": "John",
"lastName": "Smith",
"emailId": "[email protected]",
"emailVerified": true,
"2FaEnabled": false
"sub": "my-id",
"preferred_username": "John Smith",
"given_name": "John",
"family_name": "Smith",
"email": "[email protected]",
"email_verified": true
}
}
]
Expand Down

0 comments on commit a75b8f9

Please sign in to comment.