CHAPTER 5
In the previous chapter, we covered how you can add guest users to Azure AD using the Graph API and PowerShell. In this chapter, we are going to add external users using Azure Functions. For this, we are going to call the Graph API from an Azure function that is written in C#. Adding users via Azure Functions is slightly more complicated than adding users via PowerShell, but using Azure Functions gives you complete, fine-grained, programmatic control over the process.
Before we can call the Graph API, we need to register an application in Azure AD that has the right permissions to access the Graph API. We already did this in the previous chapter. We then set these permissions directly in the Graph Explorer.
In the next section, we are going to register the app in Azure AD.

Figure 32: App registrations in Azure AD

Figure 33: Create a new registration

Figure 34: App settings

Figure 35: API permissions

Figure 36: Application permissions

Figure 37: Grant admin consent

Figure 38: Add new client secret

Figure 39: Set client secret values

Figure 40: App secret value

Figure 41: App ID and Azure AD tenant ID
We now have registered an app in Azure AD that has permissions to call Microsoft Graph. This means that we can create the guest user from our Azure function through this registration.
In the next part, we are going to create the function.
In this demonstration, we are going to create an Azure function to create the guest user in Azure AD. We are using Visual Studio Code in this example to create the function.

Figure 42: Install the Azure Functions extensions

Figure 43: Create a new function

Figure 44: Select the language

Figure 45: Select the trigger

Figure 46: Specify a name for the trigger

Figure 47: Specify a name for the function

Figure 48: Select the Access Rights

Figure 49: Open the project
Tip: MSAL enables developers to acquire tokens from the Microsoft identity platform endpoint to access secured web APIs. For more information, you can refer to this website.
dotnet add package Microsoft.Graph
dotnet add package Microsoft.Identity.Client
Code Listing 4
"AzureADAppId": "YOUR_CLIENT_ID", "AzureADTenantId": "YOUR_TENANT_ID", "AzureADAppSecret": "YOUR_CLIENT_SECRET" |

Figure 50: Azure AD registration values
Code Listing 5
using System.Net.Http; using System.Threading.Tasks; using Microsoft.Graph; using System.Threading; namespace CreateGuestUserGraph { public class AuthHandler : DelegatingHandler { private IAuthenticationProvider _authenticationProvider; public AuthHandler(IAuthenticationProvider authenticationProvider, HttpMessageHandler innerHandler) { InnerHandler = innerHandler; _authenticationProvider = authenticationProvider; } protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { await _authenticationProvider.AuthenticateRequestAsync(request); return await base.SendAsync(request,cancellationToken); } } } |
Code Listing 6
using System.Net.Http; using System.Net.Http.Headers; using System.Threading.Tasks; using Microsoft.Identity.Client; using Microsoft.Graph; namespace CreateGuestUserGraph { // This class encapsulates the details of getting a token from MSAL and exposes it via the // IAuthenticationProvider interface so that GraphServiceClient or AuthHandler can use it. // A significantly enhanced version of this class will be available from the GraphSDK team // in the future. It will support all the types of //Client Application as defined by MSAL. public class MsalAuthenticationProvider : IAuthenticationProvider { private IConfidentialClientApplication _clientApplication; private string[] _scopes; public MsalAuthenticationProvider(IConfidentialClientApplication clientApplication, string[] scopes) { _clientApplication = clientApplication; _scopes = scopes; } /// <summary> /// Update HttpRequestMessage with credentials /// </summary> public async Task AuthenticateRequestAsync(HttpRequestMessage request) { var token = await GetTokenAsync(); request.Headers.Authorization = new AuthenticationHeaderValue("bearer", token); } /// <summary> /// Acquire Token /// </summary> public async Task<string> GetTokenAsync() { AuthenticationResult authResult = null; authResult = await _clientApplication.AcquireTokenForClient(_scopes) .ExecuteAsync(); return authResult.AccessToken; } } } |
Code Listing 7
using System; using System.IO; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.WebJobs; using Microsoft.Azure.WebJobs.Extensions.Http; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Microsoft.Graph; using System.Collections.Generic; using Microsoft.Identity.Client; namespace CreateGuestUserGraph { public static class HttpTriggerCSharp1 { private static GraphServiceClient _graphServiceClient; [FunctionName("HttpTriggerCSharp1")] public static async Task<IActionResult> Run( [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, ILogger log) { log.LogInformation("C# HTTP trigger function processed a request."); string firstname = req.Query["firstname"]; string lastname = req.Query["lastname"]; string emailaddress = req.Query["emailaddress"]; string requestBody = await new StreamReader(req.Body).ReadToEndAsync(); dynamic data = JsonConvert.DeserializeObject(requestBody);
firstname = firstname ?? data?.firstname; lastname = lastname ?? data?.lastname; emailaddress = emailaddress ?? data?.emailaddress; var invitation = new Invitation { InvitedUserDisplayName = $"{firstname} {lastname}", InvitedUserEmailAddress = emailaddress, InviteRedirectUrl= "https://myapplications.microsoft.com/", InvitedUserMessageInfo = new InvitedUserMessageInfo { CustomizedMessageBody = "Hey there! Check this out. I created an invitation through an Azure Function!" }, SendInvitationMessage = true }; GraphServiceClient graphClient = GetAuthenticatedGraphClient(); var graphResult = await graphClient.Invitations .Request() .AddAsync(invitation); return graphResult != null ? (ActionResult)new OkObjectResult($"Following user created: {firstname}, {lastname}, {emailaddress}") : new BadRequestObjectResult("Please provide guest user information details on the query string or in the request body."); } private static GraphServiceClient GetAuthenticatedGraphClient() { var authenticationProvider = CreateAuthorizationProvider(); _graphServiceClient = new GraphServiceClient(authenticationProvider); return _graphServiceClient; } private static IAuthenticationProvider CreateAuthorizationProvider() { var clientId = System.Environment.GetEnvironmentVariable("AzureADAppId", EnvironmentVariableTarget.Process); var clientSecret = System.Environment.GetEnvironmentVariable("AzureADAppSecret", EnvironmentVariableTarget.Process); // var redirectUri = System.Environment.GetEnvironmentVariable("AzureADAppRedirectUri", EnvironmentVariableTarget.Process); var tenantId = System.Environment.GetEnvironmentVariable("AzureADTenantId", EnvironmentVariableTarget.Process); var authority = $"https://login.microsoftonline.com/{tenantId}/v2.0"; //this specific scope means that application will default to what is defined in the application registration rather than using dynamic scopes List<string> scopes = new List<string>(); scopes.Add("https://graph.microsoft.com/.default"); var cca = ConfidentialClientApplicationBuilder.Create(clientId) .WithAuthority(authority) // .WithRedirectUri(redirectUri) .WithClientSecret(clientSecret) .Build(); return new MsalAuthenticationProvider(cca, scopes.ToArray()); } } } |

Figure 51: Debugging the function locally

Figure 52: Output after creating the guest user

Figure 53: Deploying the function from VS Code

Figure 54: Sign in to Azure

Figure 55: Create a new Function App

Figure 56: Specify a unique name

Figure 57: Pick the region in Azure
The Function App will now be deployed to Azure. If you navigate to the Azure portal after deployment, you will see that the function is deployed:

Figure 58: Deployed Azure function
We have now created a guest user in Azure AD using an Azure function written in C#. This function uses the Microsoft.Graph and the Microsoft.Identity.Client NuGet packages, and an Azure AD app registration to get access to the Azure AD tenant.
In this chapter, we have covered how you can add guest users to Azure AD B2B using an Azure AD app registration, an Azure function, and the Graph API. This Azure function was built in VS Code. In the next chapter, we are going to cover how you can manage access using Azure AD B2B entitlement management.