MicrosoftDocs / microsoft-authentication-library-dotnet

📚 Documentation repository for MSAL.NET
https://learn.microsoft.com/entra/msal/dotnet/
Creative Commons Attribution 4.0 International
20 stars 30 forks source link

TokenAcquirerTokenCredential has no documentation on how to implement it in full. #133

Closed wrharper-AASP closed 10 months ago

wrharper-AASP commented 1 year ago

This page states that 'TokenAcquisitionTokenCredential' is obsolete: 'Rather use TokenAcquirerTokenCredential'. However, there appears to be no object/library associated with TokenAcquirerTokenCredential?


Document Details

Do not edit this section. It is required for learn.microsoft.com ➟ GitHub issue linking.

localden commented 1 year ago

This API (TokenAcquirerTokenCredential) comes from a different package. We're in the process of getting the documentation for it onboarded.

localden commented 1 year ago

The API is now documented: https://learn.microsoft.com/dotnet/api/microsoft.identity.web.tokenacquirertokencredential?view=msal-model-dotnet-latest

Thanks for calling this out, @wrharper-AASP

wrharper-AASP commented 1 year ago

Updating to this breaks my auth? This doc doesn't say how to implement this on Blazor server side. current auth:

var builder = WebApplication.CreateBuilder(args);

var initialScopes = builder.Configuration["DownstreamApi:Scopes"]?.Split(' ') ?? builder.Configuration["MicrosoftGraph:Scopes"]?.Split(' ');

// Add services to the container.
/*builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; //if you dont use Jwt i think you can just delete this line
}).AddCookie()*/
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
        .EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
.AddMicrosoftGraph(builder.Configuration.GetSection("MicrosoftGraph"))
            .AddInMemoryTokenCaches(options => { options.AbsoluteExpirationRelativeToNow = new TimeSpan(0, 10, 0); })
            .AddInMemoryTokenCaches();
            //.AddSessionTokenCaches();
builder.Services.AddControllersWithViews(options =>
{
    var policy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
    options.Filters.Add(new AuthorizeFilter(policy));
}).AddMicrosoftIdentityUI();

builder.Services.AddCors(options =>
{
    options.AddDefaultPolicy(policy =>
    {
        policy.WithOrigins().AllowAnyOrigin()
                            .AllowAnyHeader()
                            .AllowAnyMethod()
                            .AllowCredentials();
    });
});
builder.Services.AddAuthorization(options =>
{
    // By default, all incoming requests will be authorized according to the default policy
    options.FallbackPolicy = options.DefaultPolicy;
});

builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor()
    .AddMicrosoftIdentityConsentHandler();
localden commented 1 year ago

Adding @jmprieur @jennyf19 to help investigate.

wrharper-AASP commented 1 year ago

are there any updates on this one?

jmprieur commented 1 year ago

@wrharper-AASP : it's in Microsoft.Identity.Web.Azure, which you need to reference separately since Microsoft.Identity.Web 2.x

wrharper-AASP commented 1 year ago

Yes, and when I do that, i get a lot of issues. This auth does not work with this change.

wrharper-AASP commented 1 year ago

I would need to know how to convert this into whatever this new way is and still keep it OpenIdConnect

jmprieur commented 1 year ago

What issues do you get, @wrharper-AASP Do you have repro steps?

wrharper-AASP commented 1 year ago

it's already here, just try to make a blazor project with that and use TokenAcquirerTokenCredential

wrharper-AASP commented 1 year ago

close was a misclick

jmprieur commented 1 year ago

@wrharper-AASP What are you trying to do? What are you trying to call from your controller?

wrharper-AASP commented 1 year ago

It's not MVC or API. It's a straight blazor server. So no Controller or API calls, just web pages. Here is a small page example:

<AuthorizeView>
    <Authorized>
<div style="border-bottom: 1px solid #d6d5d5; justify-content: flex-end; height: 3.5rem; display: flex; align-items: center;">
                <div style="white-space: nowrap; margin-left: 1.5rem;">
                    Hello, @context.User.Identity?.Name
                </div>
            </div>
    </Authorized>
    <NotAuthorized>
        <div class="top-row px-4 auth" style="">
            <a href="MicrosoftIdentity/Account/SignIn">Log in</a>
        </div>
    </NotAuthorized>
</AuthorizeView>
@code {

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await base.OnAfterRenderAsync(firstRender);
        if (firstRender)
        {
            try
            {
                await sm.Init(TokenAcquisitionService);
                sm.client = HttpClientFactory.CreateClient();
            }
            catch (MicrosoftIdentityWebChallengeUserException ex)
            {
                ConsentHandler.HandleException(ex);
            }
            catch (Exception e)
            {
                    throw new Exception("Uncaught Error: " + e.ToString());
            }
        }
    }
}

inside globals: internal static readonly string[] UserReadWrite = new[] { "https://graph.microsoft.com/User.ReadWrite" };

inside sm:

internal async Task Init(ITokenAcquisition TokenAcquisitionService)
        {
            TokenCredentials = new(TokenAcquisitionService);
            //token = await delegatedToken.GetVaultToken(TokenCredentials);
            _ = await delegatedToken.GetToken(TokenCredentials, Globals.UserReadWrite);
        }

I also use a key vault scope as well.

barebones appsettings structure:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "",
    "TenantId": "",
    "ClientId": "",
    "CallbackPath": "/signin-oidc",
    "ClientSecret": "",
    "ClientCertificates": []
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "MicrosoftGraph": {
    "BaseUrl": "https://graph.microsoft.com/v1.0",
    "Scopes": "User.ReadWrite"
  }
}
wrharper-AASP commented 1 year ago

_ = await delegatedToken.GetToken(TokenCredentials, Globals.UserReadWrite); is basically just used to force the first Consent check so everyone can get permission, just think of it as: await _tokenCredential.GetTokenAsync(new TokenRequestContext(Globals.UserReadWrite), new CancellationToken());

JayAtSherweb commented 1 year ago

Also unsure on this in Blazor Server.

I'm trying to get multitenants to login using AddMicrosoftIdentityWebApp, and use that login with ArmClient to obtain the organizations list of subscription Ids.

I'm trying to use TokenAcquirerTokenCredential in a ChainedTokenCredential for the ArmClient.

I'm not sure if this is the best way to do this or not.

Searching the internet for TokenAcquirerTokenCredential and TokenAcquirerAppTokenCredential only result in 4 pages which this is one of, so hoping for some help as there really doesn't seem to be much information at all on TokenAcquirerTokenCredential and TokenAcquirerAppTokenCredential .

wrharper-AASP commented 1 year ago

Also unsure on this in Blazor Server.

I'm trying to get multitenants to login using AddMicrosoftIdentityWebApp, and use that login with ArmClient to obtain the organizations list of subscription Ids.

I'm trying to use TokenAcquirerTokenCredential in a ChainedTokenCredential for the ArmClient.

I'm not sure if this is the best way to do this or not.

Searching the internet for TokenAcquirerTokenCredential and TokenAcquirerAppTokenCredential only result in 4 pages which this is one of, so hoping for some help as there really doesn't seem to be much information at all on TokenAcquirerTokenCredential and TokenAcquirerAppTokenCredential .

ArmClient is not used on a blazor client. The server only makes calls to a REST / function app internally. It shouldn't be modifying anything directly because no users should have direct access to anything. The designed I have created is heavily locked.

ChainedTokenCredential is an incredibly slow way to do auth.

None of this is related to the issue at hand though. OpenIdConnect needs to work with this new method if it is going to be enforced.

JayAtSherweb commented 1 year ago

Making calls to the Rest API is exactly what I need to do though from what I previously stated. I just need the multitenants auth to return their subscription Ids. I have this working already in Elixir using two APIs (https://login.microsoftonline.com, https://management.azure.com), but need to move this over to blazor and use the libraries.

Sorry, I thought the "issue at hand" by your comment "This doc doesn't say how to implement this on Blazor server side.", was the lack of documentation. My bad, I'll open another one for that I guess then.

wrharper-AASP commented 1 year ago

Making calls to the Rest API is exactly what I need to do though from what I previously stated. I just need the multitenants auth to return their subscription Ids. I have this working already in Elixir using two APIs (https://login.microsoftonline.com, https://management.azure.com), but need to move this over to blazor and use the libraries.

Sorry, I thought the "issue at hand" by your comment "This doc doesn't say how to implement this on Blazor server side.", was the lack of documentation. My bad, I'll open another one for that I guess then.

Oh, yeah this is about Microsoft telling everyone to use TokenAcquirerTokenCredential in Visual Studio, but when you switch it breaks the auth and doesn't work.

jmprieur commented 1 year ago

@wrharper-AASP : there is an example of what you want to do: https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/blob/d421a31901c9fda9a901aaf495b2b28b6675da2c/3-WebApp-multi-APIs/Controllers/HomeController.cs#L58-L72

You can do the same with a Blazor app (try/cach instead of the atribute).

wrharper-AASP commented 1 year ago

@wrharper-AASP : there is an example of what you want to do: https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/blob/d421a31901c9fda9a901aaf495b2b28b6675da2c/3-WebApp-multi-APIs/Controllers/HomeController.cs#L58-L72

You can do the same with a Blazor app (try/cach instead of the atribute).

This is the old way, Microsoft wants you to use TokenAcquirerTokenCredential instead and that is the issue.

jmprieur commented 1 year ago

Who is Microsoft. @wrharper-AASP ? Could you point me to the article that wants to you use TokenAcquirerTokenCredential? Maybe we need to update this article with something newer like IDownstreamApi?

wrharper-AASP commented 1 year ago

Who is Microsoft. @wrharper-AASP ? Could you point me to the article that wants to you use TokenAcquirerTokenCredential? Maybe we need to update this article with something newer like IDownstreamApi?

that is exactly what this is about, there isn't any.

wrharper-AASP commented 1 year ago

but visual studio tells you to do it: image

jmprieur commented 1 year ago

I see. I think that now you have provided a good repro. We'll be able to help you. You probably want to post your question in the Microsoft.Identity.Web repo (with a repro like above)

wrharper-AASP commented 1 year ago

I see. I think that now you have provided a good repro. We'll be able to help you. You probably want to post your question in the Microsoft.Identity.Web repo (with a repro like above)

This new way expects everyone to convert from Microsoft.Identity.Web to Microsoft.Identity.Web.Azure

wrharper-AASP commented 1 year ago

Does no one have the ability to just move this to the correct team? The whole issue is there is no docs on how to setup this new method and if you just convert directly, you get a lot of issues.

JayAtSherweb commented 1 year ago

Same

localden commented 10 months ago

I am closing this issue in the documentation repository since the reference above is auto-generated and should be picked up once Microsoft.Identity.Web is updated with new guidance (and there is already an issue in IdWeb tracking this work).