Trigger Microsoft MFA for specific accounts using Powershell / Rest API | Entra ID (Azure AD)

RW
Rawson WadeAzure & Entra Software Engineer

Lately, I've encountered a seemingly straightforward authentication requirement: prompt users for Multi-Factor Authentication (MFA) to verify their identity outside typical authentication flows or elevate authentication for each high-risk transaction. Platforms like Ping Identity make these tasks exceptionally simple with just a few API calls you can challenge the user with an MFA request. However, Microsoft Entra ID has opted for a different approach. They haven't made any "public use" APIs are available for triggering a Microsoft Authenticator MFA challenge. However, don't click away! That doesn't mean there isn't a "publicly accessible" API that we can use to trigger an MFA Challenge.

Before you go on, It's worth noting the risks associated with using API endpoints which aren't explicitly for external use. Microsoft doesn't offer dedicated SLAs for these endpoints that I will demonstrate. However, they do offer SLAs for the services around these endpoints. Therefore, proceed with caution if you choose to use them. Or enjoy a quick educational blog 🙂.

Use Cases for Microsoft Entra Identity (Azure AD)

The code I will demonstrate below addresses the following use cases:

  1. verifying end user's identity for service desk interactions or when resetting passwords.
  2. Implementing transactional Step-Up authentication within high-risk business applications

The solution provided below isn't flawless, so I advise against implementing it blindly without considering the potential implications for your organization.

Identity Confirmation / Verification Scenario

When users call in for support or assistance, ensuring their identities is paramount for security. By incorporating MFA into the verification process, service desk personnel can add an extra layer of protection beyond simple knowledge-based questions or caller ID. This helps mitigate the risk of unauthorized access to sensitive information or accounts, particularly in scenarios where confidential information about the end user may be compromised via social engineering.

Transactional Actions within Web Apps Scenario

The other prominent scenario arises when an end user interacts with a high-risk transaction in an application that carries significant financial implications for the business. Often involving millions of dollars, such applications could allow an employee to authorizes payments to contractors within their supply chain.

In such instances, it's imperative to authenticate that the individual at the computer is indeed the correct user to be performing the action. This might not be a likely case when operating in office environments but if employees can work from off premises these risks do increase. Therefore, the risk mitigation strategy from the business is to request an MFA challenge every time the user clicks a high-risk button.

Solving This Without Transactions

I feel it's important to highlight that managing such risks can be achieved without significantly sacrificing security. For instance, you might not need to prompt the end user for MFA every time they interact with a high-risk action in your application.

Maybe every 15 minutes is ok?

Microsoft Entra ID provides a robust solution known as "Step Up Authentication" which is ready for production use. This feature combines "Authentication Contexts" and "Claims Challenges" to possibly reauthenticate and reauthorise a users against a Conditional Access Policy. This, elevates their confidence level and reducing their risk to the organisation.

Step Up Authentication Flow Diagram Entra Id (Azure AD)

Upon initial authentication to a web application, users typically enter with a standard level of privilege. For example, they are missing particular claims in their token to do high-risk actions. Therefore, When a user attempts a high-risk action, the associated API challenges them to authenticate against a particular Authentication Context. The user is redirected to the Microsoft Login screen to obtain the corresponding claim in their token.

Here is the cool part. Conditional Access Policies are tied to Authentication Contexts. Therefore, your admins can customize what rules the end user must meet to be able to get the stepped-up claims. For example, they must be within the network boundary of the organization, successful MFA and also have a hardware token in the computer. Finally, the end user is returned to the application with the fancy new token which lets me perform the high-risk action.

You are probably wondering what's the problem here. This sounds perfect. For the most part, you are 100% correct Step-up authentication works wonders. However, there are two problems to overcome.

First, you need an in-house application or a compliant client and server to handle the authentication challenge. The The unfortunate truth is that it is unlikely you have full control of the user interface and the backend server.

Second, the end user can do as many high-risk activities as they want while the token is valid. The token that the end user owns meets all the requirements to call the high-risk endpoint. E.g. "You have a stepped-up token" that will expire after 15 or 20 minutes from now. There is no truly safe way to throw the token away once it has been in the browser's memory. What happens if you leave your computer unlocked while you need to go to the bathroom? This may be a stretch but the fact is that some organisations are dealing with these risks. The consequences could be millions of dollars. To combat this they want to force an MFA every time that user clicks the high-risk button. The solution must deal with that risk boundary between PIM and business applications.

Azure Multi Factor Authentication Background

Before you see how to trigger that MFA let's just take a step back and understand what endpoints are that you will be calling. They exist for federated Active Directory Federation Services (AD FS) to push Entra ID, formerly Azure AD, MFA notifications to end users when they require a second factor 1. It allows on-premise sign-in to trigger Entra MFA to end-user devices. These services can be configured to use Entra ID MFA as either the primary or secondary authentication factor.

I discovered this capability from a single sentence in this tutorial:

Unlike with AD FS in Windows Server 2012 R2, the AD FS 2016 Microsoft Entra multifactor authentication adapter integrates directly with Microsoft Entra ID and doesn't require an on-premises Azure Multi-Factor Authentication Server

This should suggest to you that there is an API between Entra and AD FS directly. It should also give you some confidence that this API won't be deprecated anytime soon (it might change).

Full disclosure I did not reverse engineering this API. I just had the perfect Google terms to stumble on the engineer who did the deep dive. Read It Here.

You will notice that I have made some improvements with the help of some release notes which state the new URLs that we should use for resilience etc.

If you need some help building a robust implementation with this mechanism you should get in touch.

Entra ID MFA Push Demo

To get this to work I have split it up into two scripts. generateEntraMfaClientSecret.ps1 and pushMfaNotification.ps1. First, we will look at how we can get the correct authentication tokens ready to push notifications.

Microsoft Online has an Entra Id MFA Notification Client which has the app ID '981f26a1-7f43-403b-a875-f8b09b8cd720' in every single Azure tenant. This is the principal responsible for authenticating to https://adnotifications.windowsazure.com and/or https://strongauthenticationservice.auth.microsoft.com.

So what we need to do is get the object ID of the tenant's MFA client and then create a new client secret on this Service Principal. These will be the credentials we use to get an access token for the MFA notification service.

generateEntraMfaClientSecret.ps1
Connect-MgGraph -Scopes 'Application.ReadWrite.All'
# Get ID of 'Entra Id MFA Notification Client' Service Principal
$servicePrincipalId = (Get-MgServicePrincipal -Filter "appid eq '981f26a1-7f43-403b-a875-f8b09b8cd720'").Id
 
$params = @{
	passwordCredential = @{
		displayName = "My Application MFA"
	}
}
 
# Create Client Secret onto client
$secret = Add-MgServicePrincipalPassword -ServicePrincipalId $servicePrincipalId -BodyParameter $params

🎉 We have a client secret for this service principal.🎉 Now, save that secret in a safe place. Let's look at how we send a notification to verify a user.

pushMfaNotification.ps1
$secret = "..."
$email = "email@example.com"
$tenantId = "..."
$clientId = "981f26a1-7f43-403b-a875-f8b09b8cd720" # this is the same for everyone
 
Write-Host "Get MFA Client Access Token"
$body = @{
    'resource'      = 'https://adnotifications.windowsazure.com/StrongAuthenticationService.svc/Connector'
    'client_id'     = $clientId
    'client_secret' = $secret
    'grant_type'    = "client_credentials"
    'scope'         = "openid"
}
 
$mfaClientToken = Invoke-RestMethod -Method post -Uri "https://login.microsoftonline.com/$tenantId/oauth2/token" -Body $body
Write-Host "Done."
 
 
Write-Host "Send MFA challenge to the user"
$XML = @"
<BeginTwoWayAuthenticationRequest>
	<Version>1.0</Version>
	<UserPrincipalName>$email</UserPrincipalName>
	<Lcid>en-us</Lcid>
	<AuthenticationMethodProperties
		xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
		<a:KeyValueOfstringstring>
			<a:Key>OverrideVoiceOtp</a:Key>
			<a:Value>false</a:Value>
		</a:KeyValueOfstringstring>
	</AuthenticationMethodProperties>
	<ContextId>bb07a24c-e5dc-4983-afe7-a0fcdc049cf7</ContextId>
	<SyncCall>true</SyncCall>
	<RequireUserMatch>true</RequireUserMatch>
	<CallerName>radius</CallerName>
	<CallerIP>UNKNOWN:</CallerIP>
</BeginTwoWayAuthenticationRequest>
"@
 
$headers = @{ "Authorization" = "Bearer $($mfaClientToken.access_token)" }
$mfaResult = Invoke-RestMethod -uri 'https://strongauthenticationservice.auth.microsoft.com/StrongAuthenticationService.svc/Connector//BeginTwoWayAuthentication' -Method POST -Headers $Headers -Body $XML -ContentType 'application/xml'
Write-Host "Done."
 
Write-Host $mfaResult.OuterXml
 
$mfaChallengeReceived = $mfaResult.BeginTwoWayAuthenticationResponse.AuthenticationResult
$mfaChallengeApproved = $mfaResult.BeginTwoWayAuthenticationResponse.Result.Value -eq "Success"
$mfaChallengeDenied = $mfaResult.BeginTwoWayAuthenticationResponse.Result.Value -eq "PhoneAppDenied"
$mfaChallengeTimeout = $mfaResult.BeginTwoWayAuthenticationResponse.Result.Value -eq "PhoneAppNoResponse"
$mfaChallengeMessage = $mfaResult.BeginTwoWayAuthenticationResponse.Result.Message
 
Write-Host $mfaChallengeMessage
 
if($mfaChallengeReceived -eq $true -And $mfaChallengeApproved -eq $true){
    Write-Host "User Approved MFA Request"
}else{
    if($mfaChallengeDenied -eq $true){
        Write-Host "User Denied Request"
    }else{
        Write-Host "MFA Request Failed. Either request timed out or MFA is not registered against this user."
    }
}
 

We need to get an access token scoped to the notification service. We can do this by using the client id (which I have hard coded for you) and the secret which we generated before. Then, we send a token request to login.microsoftonline.com and boom you have an access token.

Finally, it's time to send that notification! Add your secret to the header, bundle the body of the request (include the user email), then send it to the long poll HTTP request.

The body of the request has the following properties which can be customized. Here is a little summary of what I know:

AttributeUsage
ContextIdCan be changed. Must be a GUID
SyncCallIf the request should be synced or async. Unless you want to poll I recommend you keep it sync and wait for the HTTP request to return
RequireUserMatchDoes the UPN need to match the end-user
CallerNameThe application requesting the MFA request. Things don't work if you change this.
CallerIPClient's IP address. Use this if you can - it should allow for location-based MFA

The method returns an XML response like so:

result
<BeginTwoWayAuthenticationResponse
	xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
	<Version>1</Version>
	<Result>
		<Value>Success</Value>
		<Message i:nil="true" />
		<Retry>false</Retry>
		<Error i:nil="true" />
		<Exception i:nil="true" />
		<RenewCert>false</RenewCert>
	</Result>
	<SessionId>7cb90bcf-a719-49e2-b770-397d12010ec9</SessionId>
	<AuthenticationResult>true</AuthenticationResult>
	<UserPrincipalName>rawson@b69771cf-e2c1-4ab3-bebc-1850008f35ed.onmicrosoft.com</UserPrincipalName>
	<AffinityUrl>https://strongauthenticationservice.auth.microsoft.com/StrongAuthenticationService.svc/Connector/EndTwoWayAuthentication?dc=SEA</AffinityUrl>
	<ValidEntropyNumber>0</ValidEntropyNumber>
</BeginTwoWayAuthenticationResponse>

The key attributes to decode are:

  1. Result.Value string representation of what happened. Examples: Success or PhoneAppDenied or PhoneAppNoResponse
  2. Result.Message associated message to the status
  3. AuthenticationResult which is a boolean representation of if the challenge was approved

You should validate that the response code is a HTTP response 200 OK and that the body has the expected Value and AuthenticationResult. I highly suggest that if the end-user denies or expires an MFA request multiple times then your system should be smart enough NOT to send another request.

The code provided on this blog is offered 'as is' and without any warranty, express or implied. Users are solely responsible for evaluating and utilizing the code at their own risk. The author of this blog shall not be liable for any damages or losses resulting from the use of the provided code.

How MFA Trigger for Microsoft Authenticator looks

Apps which use the Microsoft Authenticator outside traditional authentication flows don't provide the same amount of details to Microsoft Authenticator. This is an important detail because to make MFA more resistant against Persistent Threat Actors we have integrated features like Per App notifications and Geo-Location details from the requesting IP. When circumventing azure multi factor authentication, you lose out on these key features. Therefore, reducing the amount of confidence in the MFA challenge.

End user Microsoft Authenticator Setup (MFA Setup)

The best part of this solution is that end user don't need to set up MFA on another application. Once they have multifactor authenticator for their typically log in flows they are auto enrolled into this system too. Because it is the same.

Considerations of Entra Id MFA Push On Demand

I believe Microsoft hasn't implemented a Graph API to trigger MFA for a reason, as hard as it may be to understand. MFA fatigue is a real issue and if you prompt the user too much there is a likelihood that a malicious MFA challenge will make its way through the cracks and get approved. So instead of making your end users hate IT Security consider what risks you are trying mitigating.

Possible Questions Might Be:

  1. Is this the correct way to mitigate said risk?
  2. Could you instead implement step-up authentication?
  3. Could you use a two-step approval process instead?

Still Need Help?

This stuff can be tricky and I don't want people reading this blog post and thinking they have a golden ticket to this problem. It is more like a tactical solution. Either way, I have spent way too many hours trying to solve this problem and have alternative solutions based on different requirements. So contact us if you would like to have a chat about this problem. We don't bite and we do free consultations 🙂.

Footnotes

  1. Certificate Based Reference ↩

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.

entra id multi-factor authentication step up authentication azure ad MFA Trigger MFA Invoke MFA Microsoft Authenticator Trigger/Invoke MFA request for specific user Identity Confirmation Help Desk trigger MFA Notification Powershell Trigger Rest API Manual MFA Prompts Trigger MFA Programmatically microsoft entra identity mfa auth mfa authentication apps microsoft authenticator azure active directory begintwowayauthenticationrequest how do you have adfs emit an mfa claim to entra id api microsoft mfa strongauthenticationservice.svc mfa active directory entra mfa push azure app id 981f26a1-7f43-403b-a875-f8b09b8cd720 trigger microsoft mfa trigger for azure entra id

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.