MFA everywhere! This is THE mantra that every organization should adopt to protect access to its resources and sensitive data. Whether it is access to e-mail, HR systems, financial data or cloud applications, MFA must be an integral and integrated part of it.

Of the various MFA solutions available, Microsoft Entra ID in combination with the Microsoft Authenticator app is certainly one of the most popular and provides a smooth and secure user experience, particularly when supported by appropriate Conditional Access policies.

However, in some cases it is necessary or preferable to have direct interfaces with APIs to integrate MFA verification into pre-existing or sensitive processes. To date, Entra ID does not provide a native method and documented API in this regard. This need prompted me to search for a solution that quickly and definitively could be integrated and easily accessible for some of the tools I use. The result is MfaOnDemand.

MfaOnDemand

MfaOnDemand is a PowerShell module designed to quickly confirm the identities of Entra ID users via Push requests to be sent to Microsoft Authenticator or even request verification via TOTP code.

Notable features are :

  • support for TOTP and Push verification.
  • designed for integration into pre-existing scripts and workflows.
  • SecretKey and Certificate-based authentication.
  • does not require any additional Enterprise App on the Tenant.
  • uses only native Microsoft APIs

Installation

MfaOnDemand is available on both GitHub and PowerShell Gallery

1
2
3
4
5
# Installation from local path
Import-Module .\MfaOnDemand.psd1

# Installation from PowerShell Gallery
Install-Module -Name MfaOnDemand

Basic usage

First, it is necessary to obtain valid credentials for using the Native MFA App of Entra ID; to do this, at least one Key must be registered:

1
$secret = Add-MoDCredentials -Provider EntraId -TenantId xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -Type Password

The Key will then be used for each MfaOnDemand request.

1
Invoke-MoDMfa -Provider EntraId -TenantId xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -Credential ($secret | ConvertTo-SecureString -AsPlainText -Force) -User [email protected] -Mode Push

Advanced usage

As already mentioned, for the use of the Native MFA App of Entra ID, credentials are required, these can be in the form of a string which is effectively a Password or in the form of a Certificate whose private key we must obviously have.
To register these credentials MfaOnDemand provides its own native Add-MoDCredentials function, which can be used like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# Register a new Password credential, valid for 1 day, and output as plain text
Add-MoDCredentials -Provider EntraId -TenantId xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -Type Password
<#
Register a new X509 Certificate credential, valid for 1 year, and output its Thumbprint,
The certificate is stored on CurrentUser Certificates Store
#>
Add-MoDCredentials -Provider EntraId -TenantId xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -Type Certificate -MyCertificate New

# Alternatively you can also register an existing X509 certificate
[X509Certificate]$cert | Add-MoDCredentials -Provider EntraId -TenantId xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -Type Certificate
# or
Add-MoDCredentials -Provider EntraId -TenantId xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -Type Certificate -MyCertificate <X509Certificate.Thumbprint>

Registering credentials with -Type Certificate requires providing the -MyCertificate parameter having one of these values:

  • ? - Starts an interactive method that allows choosing a certificate from those available in the Cert:\CurrentUser\My path.
  • New - Creates and registers a new certificate.
  • [X509Certificate] - Registers a previously obtained certificate that is stored in a variable of type [X509Certificate]
  • some_thumbprint_string - Registers a certificate that is present in the Cert:\CurrentUser\My path using its Thumbprint.
  • some_thumbprint_string_short - Search for and register a certificate present in the path Cert:\CurrentUser\My using the first 5 or more characters of its Thumbprint

To use Add-MoDCredentials you need to authenticate on the Entra ID Tenant with a user who has Application.ReadWrite.All permissions.

entra id authentication popup

The actual MFA verification is done through the Invoke-MoDMfa command.

The first time it runs it is necessary to pass the -Credential parameter in order for MfaOnDemand to authenticate to Entra ID.
Subsequent calls to Invoke-MoDMfa can omit that parameter because the session is kept active in the cache.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# Send MFA OTP request, -Credential is a Thumbprint string from an X509Certificate stored in the CurrentUser Certificates Store (Cert:\CurrentUser\My)
Invoke-MoDMfa -Provider EntraId -TenantId xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -Credential <X509Certificate.Thumbprint> -User [email protected] -Mode OTP

# Send MFA OTP request reading -Credential input from Pipeline
[X509Certificate]$cert | Invoke-MoDMfa -Provider EntraId -TenantId xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -User [email protected] -Mode OTP

# Using Pipeline is also possible to register any supported credential type and feed it to Invoke-MoDMfa
Add-MoDCredentials -Provider EntraId -TenantId xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -Type Certificate -MyCertificate New | Invoke-MoDMfa -Provider EntraId -TenantId xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -User [email protected] -Mode OTP
# or
Add-MoDCredentials -Provider EntraId -TenantId xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -Type Password | ConvertTo-SecureString -AsPlainText -Force | Invoke-MoDMfa -Provider EntraId -TenantId xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -User [email protected] -Mode OTP

Some of the potential uses and outputs of MfaOnDemand are shown in the figure.

Entra ID MfaOnDemand output

MfaOnDemand also provides another native function for easy retrieval of credentials previously registered on Entra ID: Get-MoDCredentials

1
2
# Output both Passwords and Certificates
Get-MoDCredentials -Provider EntraId -TenantId xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

Entra ID MfaOnDemand credentials

Notes

The use of Password is considered less secure than Certificate, which is why credentials added via Add-MoDCredentials -Type Password are only valid for 24 hours while those added via Add-MoDCredentials -Type Certificate are valid for 365 days.

MfaOnDemand does not handle the cleaning of credentials registered through Add-MoDCredentials. Regularly perform a timely and periodic cleanup of credentials, including both expired credentials and those no longer in use.
To simplify the cleanup Get-MoDCredentials also shows commands for removing existing Keys, use them with caution!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# Output both Passwords and Certificates
Get-MoDCredentials -Provider EntraId -TenantId xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
...
#----- USE WITH CAUTION -----
$keyId = '<KeyId>'
#** Command for password removal
    Connect-MgGraph -NoWelcome -TenantId xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -Scopes 'Application.ReadWrite.All'; Remove-MgServicePrincipalPassword -ServicePrincipalId xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -KeyId $keyId

#** Command for certificate removal
    Connect-MgGraph -NoWelcome -TenantId xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -Scopes 'Application.ReadWrite.All'; $keyCreds=(Get-MgServicePrincipal -ServicePrincipalId 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx').KeyCredentials; Update-MgServicePrincipal -ServicePrincipalId xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -KeyCredentials ($keyCreds|Where-Object { $_.KeyId -ne $keyId }) -Confirm

Invoke-MoDMfa -Credential <password> accepts as input only SecureString, the output of Add-MoDCredentials -Type Password is instead plain text and must therefore be converted via ConvertTo-SecureString.

Verification by Number Matching of Microsoft Authenticator App is not supported.

Disclaimer

MfaOnDemand is (I hope) a tool that can be useful and very versatile, however, it is important to point out a couple of thoughts that should be given due consideration.
First, MFA fatigue is a real and noticeable problem, as far as possible it is not the case to overdo the MFA checks and in case it is advisable to use -Mode OTP.
Second, potentially related to the first, MfaOnDemand uses undocumented APIs and it is easy to think that Microsoft made this choice for a good reason so better not to abuse it.

Future developments

Time and resources permitting it would be interesting to expand the project and possibly add new Providers in addition to Entra ID, so if you have use cases or MFA service providers that you would like implemented please let me know in the comments or on GitHub