NAA or BroCI…? Let Me Explain

Oct 15 2025
Share
By: Hope Walker • 12 min read

TL;DR This writeup is a summary of knowledge and resources for nested application authentication (NAA) and brokered client IDs (BroCI). 

Introduction

Microsoft introduced nested application authentication (NAA) in 2024 in this blog post. While this initial announcement was specifically for Teams, Outlook, and M365, we can now see it integrated into many more applications. NAA was introduced as a more efficient method for acquiring tokens and improving user experience. After discovering this implementation, researchers began referring to the method as brokered client ID (BroCI) due to the similarities with Family of Client IDs (FOCI). 

For clarity in this write up, NAA will refer to the authentication flow and BroCI will refer to the clients and tokens issued through brokering. Really though, the two can probably be used interchangeably and internally here, we use BroCI exclusively to distinguish it from NAA in SCCM tradecraft. There is not much documentation on NAA or BroCI at this time so this blog seeks to document some of the features to better understand the big question: What the hell did Microsoft do?

Background

NAA uses the Microsoft Authentication Library (MSAL.js) to implement the authentication flow. Applications must be configured to use NAA and use is restricted to single page applications (SPA) and extensions for applications. This is because the idea is that these are “nested” into other applications while standalone applications are used independently. Many first-party Microsoft applications are already configured for NAA. Administrators and developers can also add NAA functionality to custom applications as well.

NAA works as an alternative to on-behalf-of (OBO) authentication flows. However, nested applications may need to use this flow as well if they are interacting with other services.  The intention is to increase efficiency and user experience by avoiding multiple sign-in prompts while using the host applications.

Example of NAA

The best example is the services used in the Azure Portal. When a user logs in at https://portal.azure.com, Entra issues a token for Azure Portal (client ID c44b4083-3bb0-49c1-b47d-974e53cbdf3c). If the user wants to view conditional access policies (CAPs), they would first need to acquire a new token. The token required for viewing CAPs is for the ADIbizaUX  (client ID 74658136-14ec-4630-ad9b-26e160ff0fc6). When a user clicks on the application in the portal, the ADIbizaUX sends a request to its broker, Azure Portal, for a token. These requests can be easily identified in Burp or other applications because they include specific brokering parameters, shown below. 

The request looks similar to a normal token request, but includes specific parameters, such as brk_client_id, to indicate it is a brokered request. The token is issued to the host application and sent back to the nested application to store and use. From the user perspective, the NAA flow is seamless and they are not prompted for authentication.

In most cases, administrator portals function this way. Supporting apps are SPAs connected to the portals and when a user opens a blade or navigates to a different service, NAA occurs behind the scenes to provide authentication and reduce prompting.

Host Application

Applications using NAA have a parent-child relationship configured to facilitate authentication. There is a host application (sometimes called the parent application or broker) and a nested application (sometimes called a child application). In this dynamic, the host application works as a broker for token requests when nested applications are used within it.

The host applications are configured to act as brokers for nested applications. These are trusted Microsoft applications, such as administrator portals. This means that it is not as simple as saying a malicious application is a host application for other applications in order to get tokens. 

Host applications and nested applications open a bridge to send authentication requests and receive responses. The nested application sends a request to the NAA bridge which sends it to the host application. The host application will then use its own cached refresh token and exchange it for a BroCI token for the nested application. This relationship can be seen in the NAA Flow section below. 

Nested Application

Nested applications are SPAs or extensions for other host applications. To use NAA, the application must include information in the code of the application and add a support function (createNestablePublicClientApplication). The function includes auth information to describe the client ID of the nested application, the authentication authority, a boolean setting for supporting NAA, and a redirect URI which indicates brokering is used. Below is a partial example of what this configuration looks like:

const msalConfig = { 
	auth: { 
		clientId: "your_client_id", 
		authority: "https://login.microsoftonline.com/{your_tenant_id}",
		supportsNestedAppAuth: true 
	}, 
}

With NAA, the nested application will not directly send token requests to Entra ID. Nested applications will start by checking the local cache for tokens it already has acquired using acquireTokenFromCache. This is because host applications can be configured to prefetch tokens. Prefetching is configured in the host application’s integration manifest and indicates the host application should prefetch BroCI tokens for the listed nested applications. If tokens are already cached, the nested applications will use that token.

When the nested application needs a new token, it will send a request over the NAA bridge to the host application. The nested application will use acquireTokenSilent to get a token without prompting the user. If the nested application needs to interact with other services to perform tasks, it will need to get tokens through an OBO flow. If the nested application cannot get a token from these methods, it should be configured to have fallback options.

NAA Flow

I find it helpful to have visuals for understanding authentication flows, so below is a step by step layout of the process of getting BroCI tokens through the NAA flow. 

NAA token prefetch flow:

NAA token prefetch flow steps:

  1. User starts host application such as an admin portal or Teams
  2. Host application prefetches tokens for nested applications with a brokered request based on integration manifest
  3. Entra sends host application tokens for nested application
    1. The host application will cache these for later use
  4. User loads nested application
  5. Nested application sends token request to host application over NAA bridge
  6. Host application checks for cached tokens for nested application
  7. Host application provides cached tokens over NAA Bridge
  8. Nested application loads for user using prefetched cached token

NAA token flow without prefetch:

NAA token flow without prefetch steps:

  1. User starts the host application such as an admin portal or Teams
  2. User loads nested application
  3. Nested application sends token request to host application over NAA bridge
  4. Host application checks for cached tokens that were prefetched
  5.  Host application send its refresh token with BroCI request to Entra
  6. Entra sends host application tokens for nested application
  7. Host application provides nested application tokens to the nested application over NAA Bridge
  8. Nested application loads for user

BroCI Tokens

The normal expiration for most refresh tokens is 90 days, but BroCI refresh tokens work a bit differently. BroCI tokens have a 24-hour refresh token lifetime, which is much shorter than normal refresh tokens. This is because refresh tokens for SPAs have a default 1 day lifetime. These refresh tokens carry over the expiration when exchanged for new tokens. This means a new authentication request is needed, either via direct token request or brokered token request, to get new tokens when the refresh token expires. Below is an example of the error message received from an expired refresh token for an SPA:

AADSTS700084: The refresh token was issued to a single page app (SPA), and therefore has a fixed, limited lifetime of 1.00:00:00, which cannot be extended. It is now expired and a new sign in request must be sent by the SPA to the sign in page. The token was issued on 2025-09-09T15:16:30.0287684Z. Trace ID: f184e7ea-0094-4094-97bb-80296427be00 Correlation ID: 4a0e1dcb-c9a8-4041-9f8d-aa34c86eb7cd Timestamp: 2025-09-10 16:29:37Z",

There is some good news, though. Claims such as the authentication methods reference (amr), which indicates what factors were used in the initial authentication, carry over to BroCI tokens. This makes sense since the intention is to reduce prompting so a user does not have to complete MFA prompts each time they interact with a new service.

Brokered Applications

This is cool and all, but how does an attacker know what applications can be brokered? Remember how I said researchers were looking into this for a while now? Luckily, these awesome researchers have released resources that can help. From zh54321 there is GraphPreConsentExplorer. This repository contains a web GUI that loads a YAML file with information about applications and copyable commands to use with EntraTokenAid.

Additionally,  Dirk-jan Mollema and Fabian Bader recently released entrascopes where more information about applications and permissions are in a searchable format. The project lays out detailed information about applications in the Entra and Azure ecosystem. Filters allow you to search for BroCI applications and get information about the scopes, redirect URIs and more. 

Though I haven’t tried this myself (ran out of time), you could in theory identify custom applications that are using the NAA flow. In order to use NAA, applications need to have a redirect URL configured: brk-multihub://<your_domain>. This setting adds the brokers as a redirect URI so the parent application can make brokered requests and send it back to the application. This means that when enumerating applications registered in a tenant, NAA enabled custom applications can be identified by this setting.

BroCI Requests

The cool thing about BroCI is that token requests can be performed completely independently of the host or nested application. It does require a refresh token for one of the host applications, but requests can be sent from the command line or other tooling. 

I’m not going to go into a lot of detail here on how the requests differ from normal token requests. A detailed explanation of NAA requests and BroCI token acquisition can be found in this blog post. The post covers building requests by hand and with tooling that has added BroCI functionality. Admittedly, I got ahead of myself releasing that one first, but I am an excitable nerd. 

As a quick recap, below are the elements that comprise a NAA request: 

  • grant_type
    • Describes the type of token that is included
    • Must be a refresh token
    • Example: grant_type=refresh_token
  • refresh_token
    • Refresh token value for host application
    • Example: refresh_token=<refresh token contents>
  • redirect_uri
    • Redirect for the broker
    • The format for this starts with brk then the application client ID GUID, followed by the URL for the portal or application
    • Example: redirect_uri=brk-c44b4083-3bb0-49c1-b47d-974e53cbdf3c://portal.azure.com
  • client_id
    • Client ID for the target application you want the BroCI token for
    • Example: client_id=74658136-14ec-4630-ad9b-26e160ff0fc6
  • scope
    • Scopes you want to request for the application 
    • If not specified, then tokens are issued with the default scopes for the application
    • Example: scope=https://graph.microsoft.com/.default
  • brk_client_id
    • Client ID of the host application
    • Example: brk_client_id=c44b4083-3bb0-49c1-b47d-974e53cbdf3c
  • brk_redirect_uri
    • URI for the host application 
    • Example: brk_redirect_uri=https://portal.azure.com/

Limitations

The application targeted for a NAA request must be used within the tenant. This is due to the consent requirements for NAA to work. If the application does not have consent in the tenant, the request for tokens will be denied. 

BroCI tokens also have a shorter lifetime. However, as long as the refresh token for the host application is valid, new BroCI tokens can be acquired. There does not appear to be a limit I have seen on how many times a token can be exchanged for BroCI tokens for nested applications. 

OPSEC

All requests regardless of success or failure will be logged. In Entra, these are logged as non-interactive user sign-ins. Since this activity happens normally as users interact with host applications and the nested applications it supports, there is not much to distinguish them from normal activity. That being said, abnormal activity, such as multiple token requests to services not used in the tenant can identify malicious activity. Below is an example of sign-in logs which were logged during testing and produced many failed logon events. 

While one or two failures may fall under the radar, numerous failures like this can indicate that an attacker is trying to acquire tokens in an automated fashion to see what a user has access to. 

Digging into some of the errors can also reveal mistakes when making BroCI token requests. Below is an example of a failed request where the reply address did not match the broker client that Entra has configured for that application. 

Another example is sign-in logs for applications which do not have consent in the tenant. As mentioned before, if there is no consent for an application tokens cannot be acquired for it. Below is an example of one such log where a BroCI token was requested but the application does not have consent. 

To avoid potentially tipping off defenders, ensuring the request is properly formatted will prevent this activity from standing out or failing.