Configure a custom claim provider token issuance event (preview)

This article describes how to configure and set up a custom claims provider with the token issuance start event type. This event is triggered right before the token is issued, and allows you to call a REST API to add claims to the token.

This how-to guide demonstrates the token issuance start event with a REST API running in Azure Functions and a sample OpenID Connect application. Before you start, take a look at following video, which demonstrates how to configure Microsoft Entra custom claims provider with Function App:

Prerequisites

Step 1: Create an Azure Function app

Tip

Steps in this article may vary slightly based on the portal you start from.

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 with your administrator account.

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

  3. In the New page, select Compute > Function App.

  4. On the Basics page, use the function app 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 -.
    Publish 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 Version of the .NET runtime.
    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.

  6. Select the Notifications icon in the upper-right corner of the portal and watch for the Deployment succeeded message. Then, 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 your Function App, from the menu select Functions.
  2. From the top menu, select + Create.
  3. In the Create Function window, leave the Development environment property as Develop in portal, and then select the HTTP trigger template.
  4. Under Template details, enter CustomAuthenticationExtensionsAPI for the New Function property.
  5. For the Authorization level, select Function.
  6. Select Create

The following screenshot demonstrates how to configure the Azure HTTP trigger function.

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

1.2 Edit the function

  1. From the menu, select Code + Test

  2. Replace the entire code with the following code snippet.

    #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 claims, including the original correlation ID, the version of your Azure Function, date of birth and custom role that is returned to Microsoft Entra ID.

  3. From the top menu, select Get Function Url, and copy the URL. In the next step, the function URL will be used and referred to as {Function_Url}.

Step 2: Register a custom authentication extension

In this step, you 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. Sign in to the Microsoft Entra admin center as at least an Application Administrator and Authentication Administrator.

  2. Browse to Identity > Applications > Enterprise applications.

  3. Select Custom authentication extensions, and then select Create a custom authentication extension.

  4. In Basics, select the tokenIssuanceStart event and select Next.

  5. 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.
  6. Select Next.

  7. In API Authentication, select the Create new app registration option to create an app registration that represents your function app.

  8. Give the app a name, for example Azure Functions authentication events API.

  9. Select Next.

  10. 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
  11. Select Next and Create, which registers the custom authentication extension and the associated application registration.

After your custom authentication extension is created, open the Overview tab of the new custom authentication extension.

From the Overview page, select the Grant permission button to give admin consent to the registered app, which allows the custom authentication extension to authenticate to your API. The custom authentication extension uses client_credentials to authenticate to the Azure Function App using the Receive custom authentication extension HTTP requests permission.

The following screenshot shows how to grant permissions.

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).

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

3.1 Register a test web application

  1. Sign in to the Microsoft Entra admin center as at least an Application Administrator.
  2. Browse to Identity > Applications > Application registrations.
  3. Select New registration.
  4. Enter a Name for the application. For example, My Test application.
  5. Under Supported account types, select Accounts in this organizational directory only.
  6. In the Select a platform dropdown in Redirect URI, select Web and then enter https://jwt.ms in the URL text box.
  7. Select Register to complete the app registration.

The following screenshot shows how to register the My Test application.

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

3.1 Get the application ID

In your app registration, under Overview, 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 propety.

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.

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

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.

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:

First assign the custom authentication extension as a custom claims provider source:

  1. Sign in to the Microsoft Entra admin center as at least an Application Administrator.

  2. Browse to Identity > Applications > Application registrations.

  3. In the Overview page, under Managed application in local directory, select My Test application.

  4. Under Manage, select Single sign-on.

  5. Under Attributes & Claims, select Edit.

    Screenshot that shows how to configure app claims.

  6. Expand the Advanced settings menu.

  7. Select Configure against Custom claims provider.

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

  9. 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. You can repeat this process to add the customClaimsProvider.customRoles, customClaimsProvider.apiVersion and customClaimsProvider.correlationId attributes.

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.

Note

If the Azure function app is hosted in a different Azure tenant than the tenant in which your custom authentication extension is registered, skip to using OpenID Connect identity provider step.

  1. Sign in to the Azure portal.

  2. Navigate and select the function app you previously published.

  3. Select Authentication in the menu on the left.

  4. Select Add Identity provider.

  5. Select Microsoft as the identity provider.

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

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

  8. Unselect the Token store option.

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

    Screenshot that shows how to add authentication to your function app.

5.1 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:

  1. Sign in to the Azure portal, then navigate and select the function app you previously published.

  2. Select Authentication in the menu on the left.

  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. In the Microsoft Entra admin center:

    1. Select the Azure Functions authentication events API app registration you created previously.
    2. Select Certificates & secrets > Client secrets > New client secret.
    3. Add a description for your client secret.
    4. Select an expiration for the secret or specify a custom lifetime.
    5. Select Add.
    6. Record the secret's value for use in your client application code. This secret value is never displayed again after you leave this page.
  9. Back to the Azure Function, under the App registration, enter the Client secret.

  10. Unselect the Token store option.

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

Step 6: Test the application

To test your custom claim provider, follow these steps:

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

    https://login.microsoftonline.com/{tenant-id}/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 {tenant-id} 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 registration ID.

  4. 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.

Next steps