Traditional onboarding: create user, set temporary password, user changes password, user sets up MFA. What if users never had a password at all?
The Goal
New employee joins:
- IT creates account (no password)
- IT generates Temporary Access Pass (TAP)
- User uses TAP to register FIDO2 key or Windows Hello
- User authenticates with passkey from day one
- Password? What password?
Enabling Temporary Access Pass
Authentication Methods Policy
Connect-MgGraph -Scopes "Policy.ReadWrite.AuthenticationMethod"
$tapConfig = @{
"@odata.type" = "#microsoft.graph.temporaryAccessPassAuthenticationMethodConfiguration"
"id" = "TemporaryAccessPass"
"state" = "enabled"
"defaultLifetimeInMinutes" = 480 # 8 hours
"defaultLength" = 12
"minimumLifetimeInMinutes" = 60
"maximumLifetimeInMinutes" = 480
"isUsableOnce" = $false
"includeTargets" = @(
@{
"targetType" = "group"
"id" = "all_users"
"isRegistrationRequired" = $false
}
)
}
Update-MgPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration `
-AuthenticationMethodConfigurationId "TemporaryAccessPass" `
-BodyParameter $tapConfig
Role Requirements
To create TAPs, admins need:
- Authentication Administrator (for non-admins)
- Privileged Authentication Administrator (for admins)
Creating a User Without Password
# Create user without password
$user = New-MgUser -DisplayName "Jane Smith" `
-UserPrincipalName "[email protected]" `
-MailNickname "jane.smith" `
-AccountEnabled $true `
-PasswordProfile @{
ForceChangePasswordNextSignIn = $false
}
# Generate TAP immediately
$tap = New-MgUserAuthenticationTemporaryAccessPassMethod `
-UserId $user.Id `
-LifetimeInMinutes 480 `
-IsUsableOnce $false
Write-Host "TAP for $($user.UserPrincipalName): $($tap.TemporaryAccessPass)"
Write-Host "Valid until: $($tap.ValidFrom.AddMinutes(480))"
The Onboarding Flow
Step 1: IT Creates TAP
# Script for helpdesk
param(
[string]$UserPrincipalName
)
$tap = New-MgUserAuthenticationTemporaryAccessPassMethod `
-UserId $UserPrincipalName `
-LifetimeInMinutes 480 `
-IsUsableOnce $false
# Generate onboarding email
$emailBody = @"
Welcome to Company!
Use this temporary access code to set up your account:
Code: $($tap.TemporaryAccessPass)
Valid until: $($tap.ValidFrom.AddMinutes(480).ToString("f"))
Steps:
1. Go to https://aka.ms/mfasetup
2. Enter your email: $UserPrincipalName
3. When prompted, enter the code above
4. Follow prompts to register your security key
Need help? Contact IT at [email protected]
"@
# Send via Graph or your email system
Step 2: User Registers Passkey
User visits https://aka.ms/mfasetup:
- Enters email address
- Enters TAP when prompted
- Gets prompted to add security info
- Registers FIDO2 key (YubiKey, etc.)
- Done - no password ever set
Step 3: User Signs In
From now on, user authenticates with FIDO2 key:
- Insert key
- Touch/PIN
- Authenticated
Conditional Access Enforcement
Require strong authentication methods:
{
"displayName": "Require passwordless MFA",
"state": "enabled",
"conditions": {
"users": {
"includeUsers": ["All"]
},
"applications": {
"includeApplications": ["All"]
}
},
"grantControls": {
"operator": "OR",
"authenticationStrength": {
"id": "00000000-0000-0000-0000-000000000004" # Phishing-resistant MFA
}
}
}
Handling Edge Cases
User Loses FIDO2 Key
Generate another TAP to register a new key:
New-MgUserAuthenticationTemporaryAccessPassMethod `
-UserId "[email protected]" `
-LifetimeInMinutes 60 `
-IsUsableOnce $true # One-time use for recovery
User Needs Password for Legacy App
Some apps don't support modern auth. Options:
- Migrate the app (preferred)
- Create app password (if using MFA)
- Set a password as last resort
Shared Device Scenarios
For shared workstations, Windows Hello works better than FIDO2 keys that users carry.
Monitoring
Track TAP usage:
AuditLogs
| where TimeGenerated > ago(7d)
| where OperationName == "Admin registered temporary access pass method"
or OperationName == "User registered temporary access pass method"
| project TimeGenerated, InitiatedBy.user.userPrincipalName, TargetResources[0].userPrincipalName
// Sign-ins with TAP
SigninLogs
| where TimeGenerated > ago(24h)
| where AuthenticationMethodsUsed has "TemporaryAccessPass"
| project TimeGenerated, UserPrincipalName, Status.errorCode
Benefits
- No password to forget - Users never create one
- No password to phish - Can't steal what doesn't exist
- Simpler onboarding - No "change password on first login"
- Better security - FIDO2/passkeys are phishing-resistant
- Happier users - Modern, fast authentication
Need help implementing passwordless authentication? Get in touch - we help organisations modernise their identity security.