Issue with Acquiring Access Token for Azure Function via Azure AD B2C Authentication

RT 20 Reputation points
2025-05-20T16:09:49.9133333+00:00

I am currently facing an issue with acquiring an access token for an Azure Function after authenticating the user via Azure AD B2C. The user successfully logs in, but when attempting to trigger an Azure Function that requires an access token, I receive the following error:

Error is happening on this line of the code
// Try acquiring the access token silently
string accessToken = await tokenAcquisition.GetAccessTokenForUserAsync(scopes);

Error Message:

pgsql
Copy
MsalUiRequiredException: No account or login hint was passed to the AcquireTokenSilent call.

Steps to Reproduce:

The user authenticates via Azure AD B2C and completes the sign-in process.

After successful authentication, the application attempts to acquire an access token for an Azure Function using the ITokenAcquisition.GetAccessTokenForUserAsync() method.

The following error occurs: MsalUiRequiredException: No account or login hint was passed to the AcquireTokenSilent call.

What I Have Tried:

I have configured both Access Tokens and ID Tokens in the Azure AD B2C app registration under the Tokens section.

The Azure AD B2C app has been granted permission to access the Azure Function API with the correct scope (api://{azure-function-client-id}/.default).

I have attempted to handle the MsalUiRequiredException by triggering a reauthentication flow, but the issue persists.

Expected Behavior: After authenticating the user, I expect the app to acquire an access token for the Azure Function silently (if possible). If the access token cannot be acquired silently, the app should handle this by prompting the user for consent or reauthentication.

Code where the issue occurs:

csharp
Copy
option.Events.OnTokenValidated = async context =>
{
    // Extract user claims (for example, user principal, object ID, etc.)
    var claims = context.Principal.Claims;
    var signClaimUser = new SignClaimModel
    {
        email = claims.FirstOrDefault(c => c.Type == "emails" || c.Type == "email")?.Value,
        givenName = claims.FirstOrDefault(c => c.Type == "given_name")?.Value,
        surname = claims.FirstOrDefault(c => c.Type == "family_name")?.Value,
        objectId = claims.FirstOrDefault(c => c.Type == "oid")?.Value,
        userPrincipalName = claims.FirstOrDefault(c => c.Type == "upn")?.Value,
        tenantId = claims.FirstOrDefault(c => c.Type == "tid")?.Value,
    };

    // Serialize the model
    var json = JsonConvert.SerializeObject(signClaimUser);
    var content = new StringContent(json, Encoding.UTF8, "application/json");

    // Prepare HTTP client to call the Azure Function
    using var httpClient = new HttpClient();

    // Get the function URL and key from your appsettings.json
    var functionBaseUrl = builder.Configuration["AzureFunction:FunctionUrl"]?.TrimEnd('/');
    var functionKey = builder.Configuration["AzureFunction:FunctionKey"];
    var functionUrl = $"{functionBaseUrl}?code={functionKey}";

    // Retrieve ITokenAcquisition from the DI container to acquire a token
    var tokenAcquisition = context.HttpContext.RequestServices.GetRequiredService<ITokenAcquisition>();

    // The scope for the Azure Function (make sure your Azure Function API client ID is correctly set in appsettings.json)
    var azureFunctionApiClientId = builder.Configuration["AzureAdB2CAzureFunctionAPI:ClientId"];
    string[] scopes = new[] { $"api://{azureFunctionApiClientId}/.default" };

    try
    {
        // Try acquiring the access token silently
        string accessToken = await tokenAcquisition.GetAccessTokenForUserAsync(scopes);

        // If we get a valid access token, add it to the authorization header for the request
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

        // Call the Azure Function
        var response = await httpClient.PostAsync(functionUrl, content);

        // Optionally, handle the response (e.g., logging, error handling, etc.)
        if (!response.IsSuccessStatusCode)
        {
            var errorMessage = await response.Content.ReadAsStringAsync();
            Console.WriteLine($"Error calling Azure Function: {errorMessage}");
        }
    }
    catch (MsalUiRequiredException)
    {
        // This exception occurs if the user needs to reauthenticate and provide consent
        // Trigger the user sign-in process interactively
        var redirectUrl = context.HttpContext.Request.Scheme + "://" + context.HttpContext.Request.Host.Value + "/signin-oidc"; // Your redirect URI
        
        // Redirect the user to the sign-in page
        context.Response.Redirect(redirectUrl);
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Error acquiring token or calling Azure Function: {ex.Message}");
    }
};

Environment:

  • Azure AD B2C User Flow: ["SignUpSignIn" flow]
  • Microsoft.Identity.Web Version: [3.8.3 number of the library being used]
  • .NET Version: [Provide .NET version, e.g., .NET 9]
Community Center | Not monitored
0 comments No comments
{count} votes

Accepted answer
  1. Pradeep M 9,775 Reputation points Microsoft External Staff Volunteer Moderator
    2025-05-21T03:52:44.35+00:00

    Hi RT,

    Thank you for reaching out to Microsoft Q & A forum. 

    The error “MsalUiRequiredException: No account or login hint was passed to the AcquireTokenSilent call” typically occurs because the user’s token cache is not yet established at the point where GetAccessTokenForUserAsync() is invoked. Executing this method within the OnTokenValidated event is too early in the authentication pipeline for silent token acquisition. 

    To resolve this, it is recommended to move the token acquisition logic outside of the OnTokenValidated event, ideally to a controller or middleware stage after the user is fully authenticated and the token cache is available. 

    Additionally, please ensure that your Azure AD B2C application registration has Access Tokens enabled, and that the API permissions and scopes for the Azure Function are properly configured. 

    Also, kindly specify the Learn Path or Module you are following. This will help us understand your scenario better and provide a more precise solution. 

    If you have found the answer provided to be helpful, please click on the "Accept answer/Upvote" button so that it is useful for other members in the Microsoft Q&A community. 

    1 person found this answer helpful.
    0 comments No comments

1 additional answer

Sort by: Most helpful
  1. Bruce (SqlWork.com) 78,006 Reputation points Volunteer Moderator
    2025-05-21T20:21:54.34+00:00

    as suggested in OnTokenValidated event, the token has not been added to other middleware. If you want to use token in the event, its:

    var accessToken = context.SecurityToken as JwtSecurityToken;

    1 person found this answer helpful.
    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.