Aakash Bhardwaj SharePoint, Office 365 and Azure

Implement On-Behalf-Of Flow using C# Azure Function

Introduction

Anyone who has tried to call Graph API from a Teams app using Single Sign-On must have come across an authentication flow called On-Behalf-Of. The OAuth 2.0 On-Behalf-Of (OBO) flow is used when an app calls an API that needs to call another API on behalf of the logged-in user.

In this flow, the middle-tier service expects a user access token from the calling app and uses it, along with an Azure AD app’s credentials, to secure another access token for calling the downstream service. In this article, we will discuss how to use a C# based Azure Function as the middle-tier API to fetch an access token for calling the downstream API, Microsoft Graph.

Scenario

OBOFlowDiagram

  1. An HTTP-triggered Azure Function is used as the middle-tier API. This function expects a user access token passed in the Authorization header when it is called from any app.
  2. The Function uses the Microsoft Authentication Library (MSAL) to exchange the user access token for another access token for accessing the downstream API, Microsoft Graph. This also requires an AAD App’s Client Id and Client Secret.
  3. The new access token is returned to the app and can be used to call Microsoft Graph.

Azure AD App Configuration

  1. Go to Azure AD and create a new app registration with an appropriate name and type of supported account. Add the redirect URL http://localhost:3000 as it would be required later in the Azure Function code. Create App Registration
  2. Go to Expose an API and set the APP URI to the default value: api://<client-id>. Expose API
  3. Add a new scope with the appropriate details as this would be required to get the first access token with which the Azure function would be called. Add Scope
  4. Create a new client secret and copy its value along with the application client id as these would be required later in the Azure function.

Azure Function to exchange token

  1. Create a new HTTP-triggered C# Azure Function using VS Code. Follow this link for reference.
  2. Add the below NuGet packages as these would be required for validating the first user access token, and exchanging it for another access token to call the downstream API.
    dotnet add package Microsoft.Identity.Client
    dotnet add package Microsoft.IdentityModel.Protocols.OpenIdConnect
    dotnet add package System.IdentityModel.Tokens.Jwt
    
  3. Before exchanging the user access token, it needs to be validated to check if the issuer, audience, and signing keys values are correct. Use the below method to validate the token.
    new JwtSecurityTokenHandler().ValidateToken
    
  4. If the token is validated, use MSAL’s AcquireTokenOnBehalfOf method to exchange the token for another access token that can access the downstream API. This method requires the scope for the downstream API that we are accessing along with the validated token.
    await app.AcquireTokenOnBehalfOf(scopes, userAssertion).ExecuteAsync();
    

The entire source code for the Azure Function is available at function-csharp-obo.

Calling the Azure Function

To call the Azure function, we would need to pass the user access token that can be exchanged for another access token from Azure AD. The below steps can be followed to retrieve the first token using OAuth 2.0 Authorization Code Flow:

  1. Access the below URL in a browser replacing the values of client_id and scope. It gets the authorization code from the authorization endpoint of AAD. https://login.microsoftonline.com/common/oauth2/v2.0/authorize?scope=api://<client_id>/user_impersonation&response_type=code&client_id=<client_id>&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fredirect
  2. Copy the value of the code query parameter from the redirected URL. It is the authorization code and will be used to obtain the access token. http://localhost:3000/redirect?code=0.AXEA6a9vzJPdfEm1IR2XGxRxxximwaI6AH9Ji17H3Z9X-OZxAAE...&session_state=da89e5c0-a92a-4fb8-84a8-415eacce1117#
  3. Using Curl or Postman, make a POST request to the below mentioned token endpoint with the code, client_id, client_secret, grant_type, scope, and redirect_uri values. https://login.microsoftonline.com/common/oauth2/v2.0/token Postman Token Request
  4. This returns the access token that will be used when calling the Azure Function.
  5. Make a POST request to the Azure Function with the access token retrieved above as the bearer authorization token. It returns the access token that can be used to call the downstream API (Microsoft Graph, in this case). Image
  6. Make a call to the downstream API https://graph.microsoft.com/v1.0/me with the access token retrieved above as the bearer authorization token. It should return the user information for the logged-in user. Image

Conclusion

In this way, Azure Functions can be used as the middle-tier API in an On-Behalf-Of flow and exchange the user access token for another higher privileged access token. Even though this article uses C# Azure Function, Node.Js functions can also be used to achieve similar functionality.