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.
Hope this will help , please let us know you need something else
Thank you