Configure a custom claim provider token issuance event (preview)

This article describes how to configure and set up a custom claims provider using a token issuance start event. You'll create a REST API using Azure Functions in the Azure portal, then register a custom authentication extension. You'll add some attributes that you expect your custom authentication extension to parse from your REST API. To test the custom authentication extension, you'll register a sample OpenID Connect application to get a token and view the claims.

The following video outlines the steps you'll replicate in this article to configure a Microsoft Entra custom claims provider with an Azure Function App:

Prerequisites

Step 1: Create an Azure Function app

In this step, you create an HTTP trigger function API in the Azure portal. The function API is the source of extra claims for your token. Follow these steps to create an Azure Function:

  1. Sign in to the Azure portal as at least an Application Administrator and Authentication Administrator.

  2. From the Azure portal menu or the Home page, select Create a resource.

  3. Search for and select Function App and select Create

  4. On the Basics page, create a function app using the settings as specified in the following table:

    Setting Suggested value Description
    Subscription Your subscription The subscription under which the new function app will be created in.
    Resource Group myResourceGroup Select and existing resource group, or name for the new one in which you'll create your function app.
    Function App name Globally unique name A name that identifies the new function app. Valid characters are a-z (case insensitive), 0-9, and -.
    Deploy code or container image Code Option to publish code files or a Docker container. For this tutorial, select Code.
    Runtime stack .NET Your preferred programming language. For this tutorial, select .NET.
    Version 6 (LTS) In-process Version of the .NET runtime. In-process signifies that you can create and modify functions in the portal, which is recommended for this guide
    Region Preferred region Select a region that's near you or near other services that your functions can access.
    Operating System Windows The operating system is pre-selected for you based on your runtime stack selection.
    Plan type Consumption (Serverless) Hosting plan that defines how resources are allocated to your function app.
  5. Select Review + create to review the app configuration selections and then select Create. Deployment takes a few minutes.

  6. Once deployed, select Go to resource to view your new function app.

1.1 Create an HTTP trigger function

After the Azure Function app is created, create an HTTP trigger function. The HTTP trigger lets you invoke a function with an HTTP request. This HTTP trigger will be referenced and called by your Microsoft Entra custom authentication extension.

  1. Within the Overview page of your function app, select the Functions pane and select Create function under Create in Azure portal.

  2. In the Create Function window, leave the Development environment property as Develop in portal. Under Template, select HTTP trigger.

  3. Under Template details, enter CustomAuthenticationExtensionsAPI for the New Function property.

  4. For the Authorization level, select Function.

  5. Select Create.

    Screenshot that shows how to choose the development environment, and template.

1.2 Edit the function

  1. From the menu, under Developer, select Code + Test.

  2. Replace the entire code with the following snippet, then select Save.

    #r "Newtonsoft.Json"
    using System.Net;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Primitives;
    using Newtonsoft.Json;
    public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
    {
        log.LogInformation("C# HTTP trigger function processed a request.");
        string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
        dynamic data = JsonConvert.DeserializeObject(requestBody);
    
        // Read the correlation ID from the Azure AD  request    
        string correlationId = data?.data.authenticationContext.correlationId;
    
        // Claims to return to Azure AD
        ResponseContent r = new ResponseContent();
        r.data.actions[0].claims.CorrelationId = correlationId;
        r.data.actions[0].claims.ApiVersion = "1.0.0";
        r.data.actions[0].claims.DateOfBirth = "01/01/2000";
        r.data.actions[0].claims.CustomRoles.Add("Writer");
        r.data.actions[0].claims.CustomRoles.Add("Editor");
        return new OkObjectResult(r);
    }
    
    public class ResponseContent{
        [JsonProperty("data")]
        public Data data { get; set; }
        public ResponseContent()
        {
            data = new Data();
        }
    }
    
    public class Data{
        [JsonProperty("@odata.type")]
        public string odatatype { get; set; }
        public List<Action> actions { get; set; }
        public Data()
        {
            odatatype = "microsoft.graph.onTokenIssuanceStartResponseData";
            actions = new List<Action>();
            actions.Add(new Action());
        }
    }
    
    public class Action{
        [JsonProperty("@odata.type")]
        public string odatatype { get; set; }
        public Claims claims { get; set; }
        public Action()
        {
            odatatype = "microsoft.graph.tokenIssuanceStart.provideClaimsForToken";
            claims = new Claims();
        }
    }
    
    public class Claims{
        [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
        public string CorrelationId { get; set; }
        [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
        public string DateOfBirth { get; set; }
        public string ApiVersion { get; set; }
        public List<string> CustomRoles { get; set; }
        public Claims()
        {
            CustomRoles = new List<string>();
        }
    }
    

    The code starts with reading the incoming JSON object. Microsoft Entra ID sends the JSON object to your API. In this example, it reads the correlation ID value. Then, the code returns a collection of customized claims, including the original CorrelationId, the ApiVersion of your Azure Function, a DateOfBirth and CustomRoles that is returned to Microsoft Entra ID.

  3. From the top menu, select Get Function Url, and copy the URL value. In the next step, the function URL will be used and referred to as {Function_Url}. It's a good idea to leave your Azure portal window open, as it'll be used again in later steps.

Step 2: Register a custom authentication extension

You'll now configure a custom authentication extension, which will be used by Microsoft Entra ID to call your Azure function. The custom authentication extension contains information about your REST API endpoint, the claims that it parses from your REST API, and how to authenticate to your REST API. Follow these steps to register a custom authentication extension:

  1. From the Home page in the Azure portal, select Microsoft Entra ID and select Enterprise applications.
  2. Select Custom authentication extensions, and then select Create a custom extension.
  3. In Basics, select the TokenIssuanceStart event type and select Next.
  4. In Endpoint Configuration, fill in the following properties:
    • Name - A name for your custom authentication extension. For example, Token issuance event.
    • Target Url - The {Function_Url} of your Azure Function URL.
    • Description - A description for your custom authentication extensions.
  5. Select Next.
  6. In API Authentication, select the Create new app registration option to create an app registration that represents your function app.
  7. Give the app a name, for example Azure Functions authentication events API.
  8. Select Next.
  9. In Claims, enter the attributes that you expect your custom authentication extension to parse from your REST API and will be merged into the token. Add the following claims:
    • dateOfBirth
    • customRoles
    • apiVersion
    • correlationId
  10. Select Next, then Create, which registers the custom authentication extension and the associated application registration.

After your custom authentication extension is created, you need to grant permissions to the API. The custom authentication extension uses client_credentials to authenticate to the Azure Function App using the Receive custom authentication extension HTTP requests permission.

  1. Open the Overview page of your new custom authentication extension. Take a note of the App ID under API Authentication, as it will be needed when adding an identity provider.

  2. Under API Authentication, select Grant permission.

  3. A new window opens, and once signed in, it requests permissions to receive custom authentication extension HTTP requests. This allows the custom authentication extension to authenticate to your API. Select Accept.

    Screenshot that shows how grant admin consent.

Step 3: Configure an OpenID Connect app to receive enriched tokens

To get a token and test the custom authentication extension, you can use the https://jwt.ms app. It's a Microsoft-owned web application that displays the decoded contents of a token (the contents of the token never leave your browser).

3.1 Register a test web application

Follow these steps to register the jwt.ms web application:

  1. From the Home page in the Azure portal, select App registrations.

  2. Select New registration.

  3. Enter a Name for the application. For example, My Test application.

  4. Under Supported account types, select Accounts in this organizational directory only.

  5. In the Select a platform dropdown in Redirect URI, select Web and then enter https://jwt.ms in the URL text box.

  6. Select Register to complete the app registration.

    Screenshot that shows how to select the supported account type and redirect URI.

  7. In the Overview page of your app registration, copy the Application (client) ID. The app ID is referred to as the {App_to_enrich_ID} in later steps. In Microsoft Graph, it's referenced by the appId property.

    Screenshot that shows how to copy the application ID.

3.2 Enable implicit flow

The jwt.ms test application uses the implicit flow. Enable implicit flow in your My Test application registration:

  1. Under Manage, select Authentication.
  2. Under Implicit grant and hybrid flows, select the ID tokens (used for implicit and hybrid flows) checkbox.
  3. Select Save.

3.3 Enable your App for a claims mapping policy

A claims mapping policy is used to select which attributes returned from the custom authentication extension are mapped into the token. To allow tokens to be augmented, you must explicitly enable the application registration to accept mapped claims:

  1. In your My Test application registration, under Manage, select Manifest.
  2. In the manifest, locate the acceptMappedClaims attribute, and set the value to true.
  3. Set the accessTokenAcceptedVersion to 2.
  4. Select Save to save the changes.

The following JSON snippet demonstrates how to configure these properties.

{
	"id": "22222222-0000-0000-0000-000000000000",
	"acceptMappedClaims": true,
	"accessTokenAcceptedVersion": 2,  
    ...
}

Warning

Do not set acceptMappedClaims property to true for multi-tenant apps, which can allow malicious actors to create claims-mapping policies for your app. Instead configure a custom signing key.

Continue to the next step, Assign a custom claims provider to your app.

Step 4: Assign a custom claims provider to your app

For tokens to be issued with claims incoming from the custom authentication extension, you must assign a custom claims provider to your application. This is based on the token audience, so the provider must be assigned to the client application to receive claims in an ID token, and to the resource application to receive claims in an access token. The custom claims provider relies on the custom authentication extension configured with the token issuance start event listener. You can choose whether all, or a subset of claims, from the custom claims provider are mapped into the token.

Follow these steps to connect the My Test application with your custom authentication extension:

To assign the custom authentication extension as a custom claims provider source;

  1. From the Home page in the Azure portal, select Enterprise applications.

  2. Under Manage, select All applications, and then select My Test application from the list.

  3. From the Overview page of My Test application, navigate to Manage, and select Single sign-on.

  4. Under Attributes & Claims, select Edit.

    Screenshot that shows how to configure app claims.

  5. Expand the Advanced settings menu.

  6. Next to Custom claims provider, select Configure.

  7. Expand the Custom claims provider drop-down box, and select the Token issuance event you created earlier.

  8. Select Save.

Next, assign the attributes from the custom claims provider, which should be issued into the token as claims:

  1. Select Add new claim to add a new claim. Provide a name to the claim you want to be issued, for example dateOfBirth.

  2. Under Source, select Attribute, and choose customClaimsProvider.dateOfBirth from the Source attribute drop-down box.

    Screenshot that shows how to add a claim mapping to your app.

  3. Select Save.

  4. Repeat this process to add the customClaimsProvider.customRoles, customClaimsProvider.apiVersion and customClaimsProvider.correlationId attributes, and the corresponding name. It's a good idea to match the name of the claim to the name of the attribute.

Step 5: Protect your Azure Function

Microsoft Entra custom authentication extension uses server to server flow to obtain an access token that is sent in the HTTP Authorization header to your Azure function. When publishing your function to Azure, especially in a production environment, you need to validate the token sent in the authorization header.

To protect your Azure function, follow these steps to integrate Microsoft Entra authentication, for validating incoming tokens with your Azure Functions authentication events API application registration. Choose one of the following tabs based on your tenant type.

Note

If the Azure function app is hosted in a different Azure tenant than the tenant in which your custom authentication extension is registered, choose the Open ID Connect tab.

5.1 Using Microsoft Entra identity provider

Use the following steps to add Microsoft Entra as an identity provider to your Azure Function app.

  1. In the Azure portal, find and select the function app you previously published.

  2. Under Settings, select Authentication.

  3. Select Add Identity provider.

  4. Select Microsoft as the identity provider.

  5. Select Workforce as the tenant type.

  6. Under App registration select Pick an existing app registration in this directory for the App registration type, and pick the Azure Functions authentication events API app registration you previously created when registering the custom claims provider.

  7. Enter the following issuer URL, https://login.microsoftonline.com/{tenantId}/v2.0, where {tenantId} is the tenant ID of your workforce tenant.

  8. Under Unauthenticated requests, select HTTP 401 Unauthorized as the identity provider.

  9. Unselect the Token store option.

  10. Select Add to add authentication to your Azure Function.

    Screenshot that shows how to add authentication to your function app while in a workforce tenant.

5.2 Using OpenID Connect identity provider

If you configured the Microsoft identity provider, skip this step. Otherwise, if the Azure Function is hosted under a different tenant than the tenant in which your custom authentication extension is registered, follow these steps to protect your function:

You'll need to create a client secret for the Azure Functions authentication events API app registration.

  1. From the Home page of the Azure portal, select Microsoft Entra ID > App registrations
  2. Select the Azure Functions authentication events API app registration you created previously.
  3. Select Certificates & secrets > Client secrets > New client secret.
  4. Select an expiration for the secret or specify a custom lifetime, add a description, and select Add.
  5. Record the secret's value for use in your client application code. This secret value is never displayed again after you leave this page.

Next, we'll add the OpenID Connect identity provider to your Azure Function app.

  1. Find and select the function app you previously published.

  2. Under Settings, select Authentication.

  3. Select Add Identity provider.

  4. Select OpenID Connect as the identity provider.

  5. Provide a name, such as Contoso Microsoft Entra ID.

  6. Under the Metadata entry, enter the following URL to the Document URL. Replace the {tenantId} with your Microsoft Entra tenant ID.

    https://login.microsoftonline.com/{tenantId}/v2.0/.well-known/openid-configuration
    
  7. Under the App registration, enter the application ID (client ID) of the Azure Functions authentication events API app registration you created previously.

  8. Return to the Azure Function, under the App registration, enter the Client secret.

  9. Unselect the Token store option.

  10. Select Add to add the OpenID Connect identity provider.


Step 6: Test the application

To test your custom claims provider, follow these steps:

  1. Open a new private browser and navigate and sign-in through the following URL.

    https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/authorize?client_id={App_to_enrich_ID}&response_type=id_token&redirect_uri=https://jwt.ms&scope=openid&state=12345&nonce=12345
    
  2. Replace {tenantId} with your tenant ID, tenant name, or one of your verified domain names. For example, contoso.onmicrosoft.com.

  3. Replace {App_to_enrich_ID} with the My Test application client ID.

  4. Go through the sign in user flow that you've configured, and accept the requested permissions.

  5. After logging in, you'll be presented with your decoded token at https://jwt.ms. Validate that the claims from the Azure Function are presented in the decoded token, for example, dateOfBirth.

See also