Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] - Unable to authenticate a user bearer token and also an application bearer token in a web api endpoint at the same time #474

Closed
plemm98 opened this issue Aug 20, 2020 · 5 comments · Fixed by #475
Assignees
Labels
documentation Improvements or additions to documentation duplicate This issue or pull request already exists fixed
Milestone

Comments

@plemm98
Copy link

plemm98 commented Aug 20, 2020

Which Version of MSAL are you using ?
Note that to get help, you need to run the latest version. Preview version are also ok.
For ADAL, please log issues to https://github.com/AzureAD/azure-activedirectory-library-for-dotnet

Platform
netcore 3.1

What authentication flow has the issue?
ClientCredential flow

Is this a new or existing app?
This is a new app or experiment

Repro

Using postman, I'm trying to call a web api using both a user bearer token or an application bearer token. In order to generate my bearer token, I'm using this code to retrieve my user bearer token :

    private async Task PrepareAuthenticatedClient()
    {
        var accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(new[] { _participantServiceScope });
        _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
        _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    }

In order to generate my application bearer token, I'm using this code to retrieve it :

        IConfidentialClientApplication testApp = ConfidentialClientApplicationBuilder.Create(@@CLIENTID@@)
            .WithClientSecret(@@SECRETKEY@@)
            .WithAuthority("https://login.microsoftonline.com/@@WEBAPI-CLIENTID@@")
            .Build();
        string[] scopes = new string[] { "https://devsegicb2c.onmicrosoft.com/@@WEBAPI-CLIENTID@@/.default" };
        var ttt = testApp.AcquireTokenForClient(scopes).ExecuteAsync().Result;

Both methods allow me to generate a bearer token. The "user" bearer token contains a "scp" claims with the scope i define. The application bearer token contains a "roles" claims with the associate role define in the manifest of my application in Azure AD.

In postman, I'm calling an API (I'm using the WebApp-Calls-WebAPI-B2C/TodoListService sample code).

The sample specifies in the startup.cs the following code :

        services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddMicrosoftWebApi(options =>
        {
            Configuration.Bind("AzureAdB2C", options);
            options.TokenValidationParameters.NameClaimType = "name";
        },
        options => { Configuration.Bind("AzureAdB2C", options); });

In postman, when I call my api endpoint using the user bearer token, i get authenticate without any issues. I'm 100% authenticate!

If I try to do the same call using the application bearer token, I receive an error message. If I replace the previous code with the following authentication, I'm able to call my api endpoint using the application bearer token.

        services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(opt =>
            {
                opt.TokenValidationParameters = new TokenValidationParameters()
                {
                    ValidAudience = "@@WEBAPI-CLIENTID@@",
                    ValidateIssuer = true,
                    ValidateIssuerSigningKey = false,
                    ValidIssuers = new[]
                    {
                        $"https://login.microsoftonline.com/{Configuration["AzureAdB2C:TenantId"]}/",
                        $"https://login.microsoftonline.com/{Configuration["AzureAdB2C:TenantId"]}/v2.0",
                        $"https://login.windows.net/{Configuration["AzureAdB2C:TenantId"]}/",
                        $"https://login.microsoft.com/{Configuration["AzureAdB2C:TenantId"]}/",
                        $"https://sts.windows.net/{Configuration["AzureAdB2C:TenantId"]}/",
                        $"https://devsegicb2c.b2clogin.com/@@WEBAPI-CLIENTID@@/v2.0/"
                    }
                };
                opt.Audience = "https://devsegicb2c.onmicrosoft.com/@@WEBAPI-CLIENTID@@";
                opt.Authority = "https://login.microsoftonline.com/@@tenant-id@@";
            }); 

But, as you guess, after replacing the AddMicrosoftWebApi with the AddJwtBearer, I'm no longer able to authenticate using the user bearer token. But everything works if I'm using the application bearer token.

When I try to use both "AddAuthentication" at the same time, I receive this error message :

System.InvalidOperationException: 'Scheme already exists: Bearer'

So, if i want to be able to authenticate both a user, and an application in my api endpoint, can you explain how to setup the startup.cs to support both types of principal at the same time?

Expected behavior
Should be able to authenticate with both bearer token.

Actual behavior
Cannot authenticate an application bearer token using the sample authorization middleware.

Possible Solution

Additional context/ Logs / Screenshots
Add any other context about the problem here, such as logs and screenshots. Logging is described at https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/logging

@plemm98 plemm98 changed the title [Bug] - Unable to authenticate a user bearer token and also an application bearer token in a web api endpoint [Bug] - Unable to authenticate a user bearer token and also an application bearer token in a web api endpoint at the same time Aug 20, 2020
@bgavrilMS bgavrilMS transferred this issue from AzureAD/microsoft-authentication-library-for-dotnet Aug 20, 2020
@pmaytak
Copy link
Contributor

pmaytak commented Aug 21, 2020

If I try to do the same call using the application bearer token, I receive an error message.

Hello @plemm98. What error specifically do you get?

@plemm98
Copy link
Author

plemm98 commented Aug 21, 2020

Hi @pmaytak,

Well, it's seem I forgot to do something really important. If anyone is having the same problem, here's the solution.

You can find the answer you looking for here :

https://docs.microsoft.com/en-us/aspnet/core/security/authorization/limitingidentitybyscheme?view=aspnetcore-3.1

This note is really important :

Only one JWT bearer authentication is registered with the default authentication scheme JwtBearerDefaults.AuthenticationScheme. Additional authentication has to be registered with a unique authentication scheme.

Now that we figure that out, we need to change at least one "JwtBearerDefaults.AuthenticationScheme". For example, I decide to add this to my first JWT bearer authentication :

        services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddMicrosoftWebApi(options =>
        {
            Configuration.Bind("AzureAdB2C", options);

            options.TokenValidationParameters.NameClaimType = "name";
        },
        options => { Configuration.Bind("AzureAdB2C", options); },
        "B2C");

Finally, just follow the documentation en add the following code in your "AddAuthorization" :

services.AddAuthorization(options =>
{
    **var defaultAuthorizationPolicyBuilder = new AuthorizationPolicyBuilder(
        JwtBearerDefaults.AuthenticationScheme,
        "B2C");
    defaultAuthorizationPolicyBuilder = 
        defaultAuthorizationPolicyBuilder.RequireAuthenticatedUser();
    options.DefaultPolicy = defaultAuthorizationPolicyBuilder.Build();**
    ............
});

And then, you have it. A working software.

@jmprieur jmprieur added the bug Something isn't working label Aug 26, 2020
@jmprieur jmprieur modified the milestone: 0.3.1-preview Aug 26, 2020
@jmprieur jmprieur added needs documentation and removed bug Something isn't working labels Aug 26, 2020
@jennyf19
Copy link
Collaborator

@pmaytak this looks like a duplicate of another one assigned to you. fyi.

@pmaytak pmaytak self-assigned this Aug 27, 2020
@pmaytak pmaytak linked a pull request Aug 28, 2020 that will close this issue
@pmaytak
Copy link
Contributor

pmaytak commented Aug 28, 2020

Thanks @plemm98 for your investigation. This is related to issue #429 and a fix in PR #475 (which will be included in the next release). Also added a small section to the wiki related to this. I'll close it as resolved/duplicate.

@pmaytak pmaytak closed this as completed Aug 28, 2020
@jmprieur jmprieur added the duplicate This issue or pull request already exists label Aug 28, 2020
@jmprieur jmprieur added this to the 0.3.2-preview milestone Aug 28, 2020
@jmprieur jmprieur added the fixed label Aug 28, 2020
@jennyf19
Copy link
Collaborator

Included in 0.4.0-preview release

@jmprieur jmprieur added the documentation Improvements or additions to documentation label Oct 23, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation duplicate This issue or pull request already exists fixed
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants