Onboarding users in ASP.NET Core using Azure AD Temporary Access Pass and Microsoft Graph

The article looks at onboarding different Azure AD users with a temporary access pass (TAP) and some type of passwordless authentication. An ASP.NET Core application is used to create the Azure AD member users which can then use a TAP to setup the account. This is a great way to onboard users in your tenant.

Code: https://github.com/damienbod/AzureAdTapOnboarding

The ASP.NET Core application needs to onboard different type of Azure AD users. Some users cannot use a passwordless authentication (yet) and so a password setup is also required for these users. TAP only works with members and we also need to support guest users with some alternative onboarding flow. Different type of user flows are supported or possible:

  • AAD member user flow with TAP and FIDO2 authentication
  • AAD member user flow with password using email/password authentication
  • AAD member user flow with password setup and a phone authentication
  • AAD guest user flow with federated login
  • AAD guest user flow with Microsoft account
  • AAD guest user flow with email code

FIDO2 should be used for all enterprise employees with an office account in the enterprise. If this is not possible, then at least the IT administrators should be forced to use FIDO2 authentication and the companies should be planning on a strategy on how to move to a phishing resistant authentication. This could be forced with a PIM and a continuous access policy for administration jobs. Using FIDO2, the identities are protected with a phishing resistant authentication. This should be a requirement for any professional solution.

Azure AD users with no computer can use an email code or a SMS authentication. This is a low security authentication and applications should not expose sensitive information to these user types.


The ASP.NET Core application uses Microsoft.Identity.Web and the Microsoft.Identity.Web.MicrosoftGraphBeta Nuget packages to implement the Azure AD clients. The ASP.NET Core client is a server rendered application and uses an Azure App registration which requires a secret or a certificate to acquire access tokens.

The onboarding application uses Microsoft Graph applications permissions to create the users and initialize the temporary access pass (TAP) flow. The following application permissions are used:

  • User.EnableDisableAccount.All
  • User.ReadWrite.All
  • UserAuthenticationMethod.ReadWrite.All

The permissions are added to a separate Azure App registration and require a secret to use. In a second phase, I will look at implementing the Graph API access using Microsoft Graph delegated permissions. It is also possible to use a service managed identity to acquire a Graph access token with the required permissions.

Onboarding members using passwordless

When onboarding a new Azure AD user with passwordless and TAP, this needs to be implemented in two steps. Firstly, a new Microsoft Graph user is created with the type member. This takes an unknown length of time to complete on Azure AD. When this is finished, a new TAP authentication method is created. I used the Polly Nuget package to retry this until the TAP request succeeds. Once successful, the temporary access pass is displayed in the UI. If this was a new employee or something like this, you could print this out and let the user complete the process.

private async Task CreateMember(UserModel userData)
	var createdUser = await _aadGraphSdkManagedIdentityAppClient

	if (createdUser!.Id != null)
		if (userData.UsePasswordless)
			var maxRetryAttempts = 7;
			var pauseBetweenFailures = TimeSpan.FromSeconds(3);

			var retryPolicy = Policy
				.WaitAndRetryAsync(maxRetryAttempts, i => pauseBetweenFailures);

			await retryPolicy.ExecuteAsync(async () =>
				var tap = await _aadGraphSdkManagedIdentityAppClient

				AccessInfo = new CreatedAccessModel
					Email = createdUser.Email,
					TemporaryAccessPass = tap!.TemporaryAccessPass
			AccessInfo = new CreatedAccessModel
				Email = createdUser.Email,
				Password = createdUser.Password

The CreateGraphMemberUserAsync method creates a new Microsoft Graph user. To use a temporary access pass, a member user must be used. Guest users cannot be onboarded like this. Even though we do not use a password in this process, the Microsoft Graph user validation forces us to create one. We just create a random password and will not return this, This password will not be updated.

public async Task<CreatedUserModel> CreateGraphMemberUserAsync
	(UserModel userModel)
	if (!userModel.Email.ToLower().EndsWith(_aadIssuerDomain.ToLower()))
		throw new ArgumentException("A guest user must be invited!");

	var graphServiceClient = _graphService

	var password = GetRandomString();
	var user = new User
		DisplayName = userModel.UserName,
		Surname = userModel.LastName,
		GivenName = userModel.FirstName,
		OtherMails = new List<string> { userModel.Email },
		UserType = "member",
		AccountEnabled = true,
		UserPrincipalName = userModel.Email,
		MailNickname = userModel.UserName,
		PasswordProfile = new PasswordProfile
			Password = password,
			// We use TAP if a paswordless onboarding is used
			ForceChangePasswordNextSignIn = !userModel.UsePasswordless
		PasswordPolicies = "DisablePasswordExpiration"

	var createdUser = await graphServiceClient.Users

	return new CreatedUserModel
		Email = createdUser.UserPrincipalName,
		Id = createdUser.Id,
		Password = password

The TemporaryAccessPassAuthenticationMethod object is created using Microsoft Graph. We create a use once TAP. The access code is returned and displayed in the UI.

public async Task<TemporaryAccessPassAuthenticationMethod?> 
	AddTapForUserAsync(string userId)
	var graphServiceClient = _graphService

	var tempAccessPassAuthMethod 
		= new TemporaryAccessPassAuthenticationMethod
		//StartDateTime = DateTimeOffset.Now,
		LifetimeInMinutes = 60,
		IsUsableOnce = true, 

	var result = await graphServiceClient.Users[userId]

	return result;

The https://aka.ms/mysecurityinfo link can be used to complete the flow. The new user can click this link and enter the email and the access code.

Now that the user is authenticated, he or she can add a passwordless authentication method. I use an external FIDO2 key.

Once setup, the user can register and authenticate. You should use at least two security keys.

This is an awesome way of onboarding users which allows users to authenticate in a phishing resistant way without requiring or using a password. FIDO2 is the recommended and best way of authenticating users and with the rollout of passkeys, this will become more user friendly as well.

Onboarding members using password 😦

Due to the fact that some companies still use legacy authentication or we would like to support users with no computer, we also need to onboard users with passwords. When using passwords, the user needs to update the password on first use. The user should add an MFA, if not forced by the tenant. Some employees might not have a computer and would like user a phone to authenticate. An SMS code would be a good way of achieving this. This is of course not very secure, so you should expect these accounts to get lost or breached and so sensitive data should be avoided for applications used by these accounts. The device code flow could be used together on a shared PC with the user mobile phone. Starting an authentication flow from a QR Code is unsecure as this is not safe against phishing but as SMS is used for these type of users, it’s already not very secure. Again sensitive data must be avoided for applications accepting these low security accounts. It’s all about balance, maybe someday soon, all users will have FIDO2 security keys or passkeys to use and we can avoid these sort of solutions.

Onboarding guest users (invitations)

Guest users cannot be onboarded by creating a Microsoft Graph user. You need to send an invitation to the guest user for your tenant. Microsoft Graph provides an API for this. There a different type of guest users, depending on the account type and the authentication method type. The invitation returns an invite redeem URL which can be used to setup the account. This URL is mailed to the email used in the invite and does not need to be displayed in the UI.

private async Task InviteGuest(UserModel userData)
	var invitedGuestUser = await _aadGraphSdkManagedIdentityAppClient
					.InviteGuestUser(userData, _inviteUrl);

	if (invitedGuestUser!.Id != null)
		AccessInfo = new CreatedAccessModel
			Email = invitedGuestUser.InvitedUserEmailAddress,
			InviteRedeemUrl = invitedGuestUser.InviteRedeemUrl

The InviteGuestUser method is used to create the invite object and this is sent as a HTTP post request to the Microsoft Graph API.

public async Task<Invitation?> InviteGuestUser
	(UserModel userModel, string redirectUrl)
	if (userModel.Email.ToLower().EndsWith(_aadIssuerDomain.ToLower()))
		throw new ArgumentException("user must be from a different domain!");

	var graphServiceClient = _graphService

	var invitation = new Invitation
		InvitedUserEmailAddress = userModel.Email,
		SendInvitationMessage = true,
			= $"{userModel.FirstName} {userModel.LastName}",
		InviteRedirectUrl = redirectUrl,
		InvitedUserType = "guest"

	var invite = await graphServiceClient.Invitations

	return invite;


Onboarding users with Microsoft Graph can be complicated because you need to know which parameters and how the users need to be created. Azure AD members can be created using the Microsoft Graph user APIs, guest users are created using the Microsoft Graph invitation APIs. Onboarding users with TAP and FIDO2 is a great way of doing implementing this workflow. As of today, this is still part of the beta release.









  1. […] Onboarding users in ASP.NET Core using Azure AD Temporary Access Pass and Microsoft Graph [#.NET #.NET Core #ASP.NET Core #Azure #Azure AD #AzureAD #Fido2 #graph #Microsoft.Identity.Web #MicrosoftGraph #tap] […]

  2. […] Onboarding users in ASP.NET Core using Azure AD Temporary Access Pass and Microsoft Graph (Damien Bowden) […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: