Home > front end >  Microsoft Graph Authentication reprocess additional claims
Microsoft Graph Authentication reprocess additional claims

Time:07-13

I'm building a simple demo application netcoreapp6.0 where I offer a sign-in button to log in users against Azure AD. For the initial login we request basic claims like 'user.read'. Now we need to acquire additional claims from our users as soon as the open specific pages on the website.

I can't get around how to acquire these claims after the user already authenticated. Microsoft has consent buttons on https://developer.microsoft.com/en-us/graph/graph-explorer which do exactly what I need. However, I can't find any documentation on the /common/reprocess/ endpoint they are using.

What we've tried so far:

Adding claims policies:

services.AddAuthorization(options => {
                options.AddPolicy("ClaimsTest", policy => policy.RequireClaim("Contacts.Read"));
                options.AddPolicy("MustHaveOneDrive", policy => policy.RequireClaim("Files.ReadWrite"));
            });

And then checking those claims like:

[Authorize(Policy="MustHaveOneDrive")]

This works. If the user does not provide the claims, access is denied. I now want to have the app to ask the user for the required claims just like Microsoft does in thei graph explorer.

I can't provide code for this as we have no idea where to start.

CodePudding user response:

Thanks for the help so far!

We've managed to succeed:

What we've done: In startup.cs

services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
        .AddMicrosoftIdentityWebApp(Configuration.GetSection("Authentication")) // Fetch Auth Data from appsettings.json
        .EnableTokenAcquisitionToCallDownstreamApi(initialScopes) // Middleware to acquire additional scopes
        .AddMicrosoftGraph(Configuration.GetSection("DownstreamApi")) // Microsoft graph to fetch user information, files, whatever
        .AddInMemoryTokenCaches(); // Should be done externally!

And that's basically it. Not too hard but hard to find (for us).

With the middleware set up we can no do this (working example):

somePage.cshtml.cs:

Add annotation tags for any upcoming scopes you might want to incrementally add.

namespace Development_Praxisworkshop.Pages;

[AuthorizeForScopes(Scopes = new[]{"files.readwrite", "Sites.Read.All"})] // What scopes are we going to request eventually
public class OneDriveFilesModel : PageModel
{
    public IDriveItemsCollectionPage files;
    public IDriveItemChildrenCollectionPage _files;

    private readonly ILogger<PrivacyModel> _logger;
    private readonly IConfiguration _config;
    private readonly ITokenAcquisition _tokenAcquisition;
    private string _accessToken;
    private readonly GraphServiceClient _graphServiceClient;
    private readonly MicrosoftIdentityConsentAndConditionalAccessHandler _consentHandler;

    public OneDriveFilesModel(ILogger<PrivacyModel> logger, 
                                IConfiguration config, 
                                ITokenAcquisition tokenAcquisition,
                                GraphServiceClient graphServiceClient,
                                MicrosoftIdentityConsentAndConditionalAccessHandler consentHandler)
    {
        _logger = logger;
        _config = config;
        _tokenAcquisition = tokenAcquisition;
        _graphServiceClient = graphServiceClient;
        this._consentHandler = consentHandler;
    }

    public void OnGet()
    {
        string[] scopes = new string[]{"files.readwrite", "Sites.Read.All"}; // scopes to be incrementally requested
        _accessToken = _tokenAcquisition.GetAccessTokenForUserAsync(scopes).Result;
        Console.WriteLine(_accessToken); // check token!
        _files = _graphServiceClient.Me.Drive.Root.Children.Request().GetAsync().Result;
    }    
}

This now requests a new set of claims if not already provided by the user. Hope this helps someone in the future!

Feel free to make sugestions if we're doing anything weird here!

The authentication config in appsettings.json looks like this:

 "Authentication": {
     "Instance": "https://login.microsoftonline.com/",
     "ClientId":"00000000-0000-0000-0000-000000000000",
     "ClientSecret": "we now need a client secret for the client to incrementally update the app registration in azure ad",
     "TenantId":"contoso.com",
     //"TenantId": "00000000-0000-0000-0000-000000000000"
     //"TenantId": "common" //multi tenant apps
     "ClientCapabilities": [ "cp1" ],
     "CallbackPath": "/signin-oidc"
}

CodePudding user response:

For additional consent using the Auth API,could you please check and follow these steps:

 1. The token retrieved using getAuthToken() must be exchanged on the
    server-side using Azure AD on-behalf-of flow to get access to those
    other Graph APIs. Ensure you use the v2 Graph endpoint for this
    exchange.
    
 2 .If the exchange fails, Azure AD returns an invalid grant exception.
    It usually responds with one of the two error messages,
    invalid_grant or interaction_required.
    
 3 .When the exchange fails, you must ask for consent. Use the user
    interface (UI) to ask the app user to grant other consent. This UI
    must include a button that triggers an Azure AD consent dialog using
    Silent authentication.
    
 4. When asking for more consent from Azure AD, you must include
    prompt=consent in your query-string-parameter to Azure AD, otherwise
    Azure AD wouldn't ask for other scopes.
    
5 . Instead of ?scope={scopes}, use ?prompt=consent&scope={scopes}
    Ensure that {scopes} includes all the scopes you're prompting the
    user for, for example, Mail.Read or User.Read. After the app user
    has granted more permissions, retry the OBO flow to get access to
    these other APIs.

ref doc - https://github.com/MicrosoftDocs/msteams-docs/blob/main/msteams-platform/tabs/how-to/authentication/tab-sso-graph-api.md

Hope this will help , please let us know you need something else

Thank you

  • Related