Skip to content

Acquiring tokens with authorization codes on web apps

Jean-Marc Prieur edited this page Dec 2, 2018 · 26 revisions

Getting tokens by authorization code (Web Sites)

When users login to Web applications (web sites) using Open Id connect, the web application receives an authorization code which it can redeem to acquire a token for Web APIs.

Getting tokens by authorization code in MSAL.NET

image

The principle is exactly the same for MSAL.NET as for ADAL.NET, and is illustrated in the active-directory-dotnet-webapp-openidconnect-v2 sample, in Startup.Auth.cs, Lines 70 to 87. ASP.NET triggers an authentication code flow because the scopes App_Start/Startup.Auth.cs#L53 contains open_id

Scope = "openid profile offline_access Mail.Read Mail.Send",

and the application subscribes to the notification when the authorization code get received App_Start/Startup.Auth.cs#L67-L72

Notifications = new OpenIdConnectAuthenticationNotifications
{
 AuthorizationCodeReceived = OnAuthorization,
 AuthenticationFailed = OnAuthenticationFailed
}

When this notification is processed it acquires a token from the authorization code by calling AcquireTokenByAuthorizationCodeAsync.

private async Task OnAuthorization(AuthorizationCodeReceivedNotification context)
{
 var code = context.Code;
 string signedInUserID = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;
 TokenCache userTokenCache = new MSALSessionCache(signedInUserID,
                                                   context.OwinContext.Environment["System.Web.HttpContextBase"] as HttpContextBase).GetMsalCacheInstance();
  ConfidentialClientApplication cca = new ConfidentialClientApplication(clientId, 
                                                                        redirectUri,
                                                                        new ClientCredential(appKey), 
                                                                        userTokenCache, 
                                                                        null);
 string[] scopes = { "Mail.Read" };
 try
 {
   // As AcquireTokenByAuthorizationCodeAsync is asynchronous we want to tell ASP.NET that we are handing the code
   // even if it's not done yet, so that it does not concurrently call the Token endpoint, otherwise you'll get
   // a  'OAuth2 Authorization code was already redeemed' error message
   context.HandleCodeRedemption();
 
  // Redeem the code
  AuthenticationResult result = await cca.AcquireTokenByAuthorizationCodeAsync(code, scopes);

  // Share the ID Token with ASP.NET, but not the Access Token, otherwise ASP.NET could prevent a further call
  // to AcquireTokenByAuthorizationCodeAsync to really get to AAD in the case of incremental consent (when the
  // Web app requires more scopes)
  context.HandleCodeRedemption(null, result.IdToken);
 }
 catch (Exception eee)
 {

 }
}

Note that the code is usable only once to redeem a token. AcquireTokenByAuthorizationCodeAsyncshould should not be called several times with the same authorization code (it's explicitly prohibited by the protocol standard spec). If you redeem the code several times, you'll get an error: 'invalid_grant', 'AADSTS70002: Error validating credentials. AADSTS54005: OAuth2 Authorization code was already redeemed, please retry with a new valid code or use an existing refresh token

If you are writing an ASP.NET / ASP.NET Core application, this might happen if you don't tell the ASP.NET/Core framework that you have already redeemed the code.

This very operation has the side effect of adding the token to the token cache, and therefore the controllers that will need a token later will be able to acquire a token silently, as does the SendMail() method of the HomeController.cs#L55-L76

Interesting samples using the authorization code flow

Sample Description
active-directory-dotnet-webapp-openidconnect-v2 Web application that handles sign on via the (AAD V2) unified Azure AD and MSA endpoint, so that users can sign in using both their work/school account or Microsoft account. The sample also shows how to use MSAL to obtain a token for invoking the Microsoft Graph.
active-directory-dotnet-admin-restricted-scopes-v2 An ASP.NET MVC application that shows how to use the Azure AD v2.0 endpoint to collect consent for permissions that require administrative consent. Topology

Getting started with MSAL.NET

Acquiring tokens

Desktop/Mobile apps

Web Apps / Web APIs / daemon apps

Advanced topics

News

FAQ

Other resources

Clone this wiki locally