↓Skip to main content

Implementing FIDO2 / YubiKey in Microsoft Entra ID Without Mobile Authenticator and handling Self-Service-Password-Reset (SSPR)

··1091 words·6 mins

Overview #

FIDO2 security keys offer a secure and convenient passwordless authentication method. For organizations where employees either lack company-issued phones or prefer not to use personal devices for authentication, this hardware token becomes a viable alternative. Here’s how to implement FIDO2/YubiKey as the sole authentication method in Microsoft Entra ID.

This guide is for mixed environments: some users only use FIDO2 keys, others still rely on the Authenticator app or SMS and therefore need SSPR. If you pre-provision FIDO2 keys for all users and enforce phishing-resistant MFA with Conditional Access, you can turn SSPR off completely – that is the more secure target state.

Without configuring a Self-Service Password Reset (SSPR) exception, users relying solely on a FIDO2/Yubikey will be prompted to add the Microsoft Authenticator.

A solution for this can be found in the chapter: Handling SSPR

Implementation Steps #

Enable FIDO2 Authentication

  • Navigate to the Microsoft Entra Admin Center.
  • Go to Entra ID > Authentication methods > Policies.
  • Enable Passkey (FIDO2) for your target users and set Allow self-service set up to Yes. For hardware keys only, use a passkey profile with device-bound passkeys and enforced attestation.

Configure Temporary Access Pass (TAP)

  • Enable TAP in Authentication Methods Settings.
  • Configure the lifetime (allowed range: 10 minutes to 30 days, by default 1 to 8 hours) and use One-time use for the initial registration.
  • Use TAP for initial FIDO2 registration and recovery scenarios.

User Registration Process

  1. Admin generates a Temporary Access Pass (TAP) for the user.
  2. The user logs in at mysignins.microsoft.com/security-info by using the TAP.
  3. The user registers their FIDO2 security key.

Security Benefits #

  • Phishing-resistant authentication
  • No dependency on mobile devices
  • Reduced password-related IT support
  • Works for Windows 10/11 sign-in on Entra-joined devices (hybrid joined: Windows 10 2004 or later) and for web applications

This setup eliminates the need for Microsoft Authenticator while maintaining robust security through hardware-based authentication tokens. Exclude these users from the registration campaign, otherwise Entra may still nudge them to set up the Authenticator.

Handling SSPR #

When a user relies solely on a FIDO2 Key, it is essential to exclude them from Self-Service Password Reset (SSPR) configurations.

Passkeys do not count as an SSPR method. FIDO2-only users recover their access with a new TAP from the helpdesk.

Since only one include group can be specified for SSPR, you must create a group containing all users except those who exclusively use FIDO2 keys. For example, if you have 100 users and need to exclude 2, you must create a group of the remaining 98 users. Nested groups are supported. SSPR requires Microsoft Entra ID P1.

Since 30 September 2025, authentication methods for MFA and SSPR can only be managed in the Authentication methods policy.

Password Properties

You have multiple possibilities in creating your SSPR Group:

  • Create a dynamic group, exclude any user who has a specific attribute and include everyone else. Disadvantage: For more than a handful people it’s a lot of manual work.
  • Create an Azure Automation that fills a group with users that are allowed to use SSPR:
    • Select all users excluding those that have a FIDO2 hardware token.
      Disadvantage: New users will be prompted to add the authenticator until the script runs
    • Select Users that have one or two SSPR compatible Authentication methods
      Disadvantage: Users that do not have an authentication method registered, will not get prompted to register one.

These options all require that you need to have a Conditional Access Policy that targets all users for MFA enrollment because of the following:

Enabling the “Require users to register when signing in?” option only applies to the group specified for SSPR registration.

Example: target all users with the grant control “Require authentication strength” and use “Phishing-resistant MFA” for FIDO2-only users.

Password reset | Registration

Azure Automation #

In this guide we will go with Option:

Select users that have at least one SSPR-compatible authentication method

Use the following Code in your Automation. (Not recommended, but you can also run this script manually) After that add the Group $groupId as SSPR-Enabled Group.

Prerequisit Modules:

  • Microsoft.Graph.Authentication, Microsoft.Graph.Users, Microsoft.Graph.Identity.SignIns, Microsoft.Graph.Groups

Required application permissions (admin consent): User.Read.All, UserAuthenticationMethod.Read.All, GroupMember.ReadWrite.All

Code: #

Code can also be found in our Repository: Samily-Scripts

## Variable Declartion Start ##

$clientId = "InsertClientID"
$tenantId = "InsertTenantID"
$thumbprint = "InsertThumbprint"
$groupId = "InsertGroupID" # Replace with the Object ID of your target group

# Insert Enabled Authentication Methods
$authMethodsToCheck = @("#microsoft.graph.microsoftAuthenticatorAuthenticationMethod", 
                        "#microsoft.graph.phoneAuthenticationMethod", 
                        "#microsoft.graph.emailAuthenticationMethod")

#Optional UPN Filter
#$UPNs = @("xyz.com",
#          "abc.com")

## Variable Declartion End ##

Connect-MgGraph -ClientId $clientId -TenantId $tenantId -CertificateThumbprint $thumbprint -NoWelcome

# Get all users in Entra ID
$users = Get-MgUser -All -ConsistencyLevel eventual -Property Id,UserPrincipalName
$totalUsers = $users.Count # Total number of users for progress tracking
$currentUser = 0         # Counter for processed users

Write-Output "Getting Users"

# Initialize list for eligible users
$eligibleUsers = @()

Write-Output "Checking Users - Outputting Status in 50 User Increments"

# Iterate through each user and check their authentication methods
foreach ($user in $users) {
    $currentUser++

    if ($currentUser % 50 -eq 0) {
        Write-Output "Checking user $currentUser/$totalUsers"
    }

    $eligible = $true
#Optional UPN Filter
#    foreach ($UPN in $UPNs) {
#        if ($user.UserPrincipalName -like "*$UPN") {
#            $eligible = $false
#            break
#        }
#    }

    if ($eligible) {
        try {
            # Retrieve authentication methods for the user
            $authMethods = Get-MgUserAuthenticationMethod -UserId $user.Id -ErrorAction SilentlyContinue

            # Extract method types
            $authMethodTypes = $authMethods | ForEach-Object { $_.AdditionalProperties["@odata.type"] }

            # Check if user has at least one of the allowed authentication methods
            $hasAllowedAuthMethod = $false
            foreach ($method in $authMethodTypes) {
                if ($authMethodsToCheck -contains $method) {
                    $hasAllowedAuthMethod = $true
                    break
                }
            }

            # Add user to eligible list only if they have an allowed method
            if ($hasAllowedAuthMethod) {
                $eligibleUsers += $user.Id
            }
        } catch {
            Write-Output "Error processing user $($user.UserPrincipalName): $_"
            continue
        }
    }
}

Write-Output "`nFinished checking users."

# Add eligible users to the group, with progress updates
$totalEligibleUsers = $eligibleUsers.Count # Total number of eligible users
$currentEligibleUser = 0                   # Counter for added eligible users
$newMembersAdded = 0

foreach ($userId in $eligibleUsers) {
    $currentEligibleUser++

    # Update progress on the same line for adding users to the group
    Write-Host -NoNewline "`rAdding eligible user $currentEligibleUser/$totalEligibleUsers to the group"

    try {
        # Check if user is already a member of the group
        $isMember = Get-MgGroupMember -GroupId $groupId -All | Where-Object { $_.Id -eq $userId }

        if (-not $isMember) {
            New-MgGroupMember -GroupId $groupId -DirectoryObjectId $userId
            $newMembersAdded++
        }
    } catch {
        Write-Output "Could not add $userId to Group."
        continue
    }
}

Write-Output "`n`n----------------------------------------`n`n"
Write-Output "Process finished - Checked $totalUsers users - $($eligibleUsers.Count) users were eligible - Added $newMembersAdded new members to group"
Emily
Author
Emily
Emily is a Modern Workplace Engineer focused on Microsoft Intune, Entra ID and automation with PowerShell.