Associate Entra External Identity User to External Systems After Signup

RW
Rawson WadeAzure & Entra Software Engineer

Managing customer identities is crucial in today's digital landscape, especially when integrating with all the external systems which drive our customers experiences with our brand. However, this seemingly simple task of broadcasting new signups to external systems may not be as simple as you would first think with Microsoft's new Entra External ID. Before we begin, if you haven't familiarised yourself with the difference of Entra External ID vs Azure B2C: Navigating Customer IAM Challenges. I recommend you check out the article and get that foundation information.

So how do we link Microsoft Entra External Id to with external systems like Stripe, MailChimp, Salesforce, or even a simple SQL database. At first glance, you might think it's straightforward to spin up a function app to intercept the signup flow (which is possible). However, it's not that simple. As we will explore further, these API calls offer limited flexibility.

the issues with OnAttributeCollectionStart and OnAttributeCollectionSubmit

These API calls can be incredibly useful for capturing user information or injecting known data into the signup form. They execute both before and after a user inputs data into the signup form. There are many exciting use cases for these APIs like Invite Only Entra External Id directory.

However, before you dive in, it's important to understand the strict rules governing the information these APIs accept and provide. First, you cannot access the user's ID because the APIs operate before a user is created. Instead, you must use the user's email (not even UPN) as an identifier for the account to be created. This can cause issues later when users want to change their email addresses.

Second, the properties you pass into the form will be ignored if they are not part of the signup flow. This means your function apps must know the exact signup flow and property names (including the app ID) that you want to edit. Using the wrong name will cause it to fail. Even worse, if your function app takes more than 2 seconds to return a response, it will cause a dead-end in the user signup process, which can be problematic for apps communicating with external systems with authentication.

As a result, setting up payment methods or subscribing to emails using these APIs can be quite challenging.

So, what's the solution, you might ask? Well, for now, it's a workaround.

User Association to External Systems

Your first call to action might be to use these Sign Up flow api calls. Which I have seen work. However, if you can suffice a delay of more than 5 minutes there is a polling method which works quite well for the time being.

Microsoft Entra External ID Customer SignUp Audit Logs

Yeah ok, I can see you closing this blog. Hear me out. If it's not directly needed within the first initial login. Isn't that ok? We know can take as much time as we need to setup external systems and we can ensure that we don't compromise the user sign up flow which is critical path for many applications.

Permissions

First, you will need to set up the appropriate permissions on an Application Registration inside your Entra External ID (Not your Entra ID!).

Permissions to assign:

  1. AuditLog.Read.All Which is a lot of permissions in terms of Personal Identifiable Information so keep this secret safe!
  2. User.ReadWrite.All: OPTIONAL This is for the use case when you want to tag information into a user's properties.

Entra Id App Registration Permissions

Then generate a certificate and store that in a KeyVault!

Function App

Now to the fun stuff. Coding 🧑‍💻! If you need help with the following part reach out to us, we work on projects big and small.

What we want to do is create a function app which will run every couple of minutes, check for a new user, and then

execute the various associations with external systems.

associateUsers.cs
#r "nuget: Azure.Identity, 1.5.0"
#r "nuget: Microsoft.Graph, 4.0.0"
 
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;
using Microsoft.Graph;
using Azure.Identity;
 
public static class FunctionApp
{
    private static readonly HttpClient httpClient = new HttpClient();
 
    [FunctionName("UpdateNewAccounts")]
    public static async Task Run([TimerTrigger("0 */5 * * * *")] TimerInfo myTimer, ILogger log)
    {
        log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
        log.LogInformation($"Last checked: {myTimer.ScheduleStatus.Last}");
 
        // Get environment variables
        string tenantId = Environment.GetEnvironmentVariable("TenantId");
        string clientId = Environment.GetEnvironmentVariable("ClientId");
        string clientSecret = Environment.GetEnvironmentVariable("ClientSecret"); // Use a KeyVault Reference or Managed Identity
        string mailchimpApiKey = Environment.GetEnvironmentVariable("MailchimpApiKey");
        string mailchimpListId = Environment.GetEnvironmentVariable("MailchimpListId");
 
        // Authenticate with Microsoft Graph
        var options = new TokenCredentialOptions { AuthorityHost = AzureAuthorityHosts.AzurePublicCloud };
        var clientSecretCredential = new ClientSecretCredential(tenantId, clientId, clientSecret, options);
        var graphClient = new GraphServiceClient(clientSecretCredential);
 
        // Query the audit logs
        //Get new user events in the 20 minutes prior to the last run
        var time = timerInfo is { IsPastDue: true, ScheduleStatus: not null }
            ? Maximum(timerInfo.ScheduleStatus.Last.Subtract(TimeSpan.FromMinutes(10)),
                DateTimeOffset.UtcNow.Subtract(TimeSpan.FromDays(5)))
            : DateTimeOffset.UtcNow.Subtract(TimeSpan.FromMinutes(10));
 
        var auditLogs = await graphClient.AuditLogs.DirectoryAudits.GetAsync(config => config.QueryParameters.Filter =
            $"category eq 'UserManagement' and activityDisplayName eq 'Add user' and activityDateTime ge {time:O}");
 
        // If you sign up flow is huge you will need to add paging code!
        foreach (var logItem in auditLogs.CurrentPage)
        {
            // Process the audit log item
            string userId = logItem.targetResources.User.Id;
            string userEmail = logItem.targetResources.User.UserPrincipalName;
 
            // Add the user to Mailchimp
            var mailchimpData = new
            {
                email_address = userEmail,
                status = "subscribed"
            };
            var mailchimpContent = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(mailchimpData));
            mailchimpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", mailchimpApiKey);
            var mailchimpResponse = await httpClient
            .PostAsync($"https://<dc>.api.mailchimp.com/3.0/lists/{mailchimpListId}/members", mailchimpContent);
            if (mailchimpResponse.IsSuccessStatusCode)
            {
                log.LogInformation($"Successfully added {userEmail} to Mailchimp.");
            }
            else
            {
                log.LogError($"Failed to add {userEmail} to Mailchimp. Response: {mailchimpResponse.ReasonPhrase}");
            }
 
            // Update the user's display name via Microsoft Graph
            var user = new User
            {
                DisplayName = "Rawson Wade"
                UserPrincipalName = "contact-us@entraneer.com" // Fix up the UPN while we are here
            };
            await graphClient.Users[userId].Request().UpdateAsync(user);
            log.LogInformation($"Successfully updated display name for user {userEmail}.");
        }
    }
}
 

You don't need to get bogged down in details for this function app. Here is they key Ideas:

Function Timing

You need to make sure that you're not associating the same user to the external systems again and again. One way to solve this is to use the last time that your function app Ran as a bench mark for your audit logs history.

Microsoft Graph Call to Audit Logs

We just care about the audit logs from this Graph API which has a lot of information. So we need to filter by the data and time of the audit log and only to the logs which are for new users. You can use Graph Explorer to try it out (FYI that link has the query ready to go) to explore what the data looks like and how you might like to use it.

Deployment

This uses simple C# Script in a consumption based Azure Function App. If you want the Bicep/ARM template you can send us a message.

Common Use cases

What are some common use cases for this system architecture:

Get User Object ID into payment system

We strive to offer the best experience for our customers while ensuring we get paid. This method allows you to associate your user with a billing profile in applications like Stripe. When it's time for them to set up their payment details, everything is already prepared. Additionally, make sure to add these details to the user object, making it easy to match Monthly Active Users with their billing information.

Enroll user in Email Campaigns

Its likely that you want to reach your customers via emails. This usecase can help with that. Lets say you have a check box in your signup flow. Then, use these function apps to read their email preference and talk to the external system like Mail Chimp to register them and send a welcome email.

Assign User Birthrights

Sometimes, we're not dealing with consumers in the traditional sense. You might be working with students or contractors who don't have workforce credentials, but you need to manage their access to your app. In these scenarios, User Access Control and even birthrights might be necessary for them to use registration systems. Assigning these users to the appropriate groups can be beneficial. However, if you require more comprehensive user access controls with advanced security features, I recommend trying out Apporetum. They offer an IAM web application for delegated access management, which is highly effective for CIAM use cases like these.

Fix User Principal Name (UPN) and DisplayName for new Entra External ID Users

Some user properties have poor default settings, making auditing and administration difficult, especially during critical times. In our projects, we've addressed this by modifying the User Principal Name (UPN) to a more readable value (not just the email, as it can change). This approach enables us to effectively identify and manage users without dealing with GUIDs.

Conclusion

I can't speak for Mircosoft but it would be very likely that an event like this will be available in the future. In the meantime hopefully you have found a good enough solution in this article to get going. As always we offer Entra Engineering and Software Development services to organisations big and small. If you want a free consultation or just need to talk it out feel free to send us a message.

RW
Rawson WadeAzure & Entra Software Engineer

© Posts are provided 'as is' under the AGPL 3.0 license unless otherwise stated

Want to be kept in the loop

Sign up to hear about the latest from the team at Entraneer. We talk anything Entra, IAM and Azure Enterprise Apps.

External User ID on SignUp entra id microsoft entra identity customer identity and access management b2c azure ad Microsoft Entra External ID External ID CIAM Solution b2c ciam Entra External ID Vs Azure B2C Rest API External ID micro soft azure azure license azure entra single sign on with azure ad Salesforce Stripe MailChimp After User SignUp entra b2c integrate with high schools entra external id vs b2c azure b2c ad entra microsoft com

Expansive Knowledge, Best in class Security, best Value in the Cyber Security and Microsoft Entra Partner Class, Highly Skilled. Preference number one. Microsoft Entra Excellence. We are your consultants for entra engineering and development. Microsoft entra engineering. Identity and Access Management Experts in Microsoft Azure, Microsoft Entra, Microsoft Entra ID and Microsoft Entra External ID. experts for microsoft entra Our team offers expansive knowledge and best-in-class security, ensuring the best value in the cyber security industry. As a top Microsoft Entra Partner, we provide highly skilled services, making us your number one preference. We excel in Microsoft Entra excellence and serve as your dedicated consultants for Entra engineering and development. Our expertise in Microsoft Entra engineering encompasses all aspects of identity and access management. We are identity and access management experts in Microsoft Azure, Microsoft Entra, Microsoft Entra ID, and Microsoft Entra External ID. Trust us as your experts for Microsoft Entra. Need help with azuread / Microsoft Entra. Talk to the trusted experts from Australia

We use cookies

We use cookies to ensure you get the best experience on our website. By clicking Accept, you agree to our use of cookies.
Learn more.