Closed FelipeCostaGualberto closed 2 years ago
@FelipeCostaGualberto
For more details see: https://github.com/AzureAD/microsoft-identity-web/wiki/multiple-authentication-schemes
PS: we have added this error, because it's very important that developers use the right authentication scheme (to get security)
Hello @jmprieur , thanks for the fast answer. I feel like I'm miles away to understand what is happening. I'll try to answer your questions, maybe some statements here will be incorrect.
AddMicrosoftIdentityWebApp
instead of AddMicrosoftIdentityWebApi
because I didn't figure out a way to show Azure's Microsoft Identity UI for the user to enter his credentals when using AddMicrosoftIdentityWebApi
.AddMicrosoftIdentityWebApi
"hijacking" my Bearer
scheme. If possible, I'd like to "normalize" every user to Bearer
scheme, being it the default scheme (is this correct or a bad practice?).Bearer
scheme in controllers because all users will get its claims built by the same function in my AccountController
, so no need to decorate them with authentication schemes (is this correct or a bad practice?).@FelipeCostaGualberto
@jmprieur you said I was correctly using AddMicrosoftIdentityWebApp
, and also that I just should use AddMicrosoftIdentityWebApi
. Can you clarify that?
Either way, if I remove my AddJwtBearer
how will I define this?
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(configuration["Jwt:SecurityKey"])),
This is important, because as you can see, Bearer
is my default scheme and my IndexController
is decored with [Authorize]
. If I don't define what is my JWT key in the server, which key the server will use to parse the Bearer
token from incoming requests?
You don't need to provide the issuer signing keys, @FelipeCostaGualberto. Microsoft.Identity.Web / ASP.NET Core / Microsoft.IdentityModel will discover them for you. They are part of the OAuth2.0 well known metadata.
You should not even provide them as IdentityModel ensures the resilience of the app vs outages of the IdP, which you don't get if you manage your keys yourself.
@jmprieur If I remove this code from the initialization:
.AddJwtBearer(options =>
{
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters()
{
NameClaimType = "sub",
RoleClaimType = "role",
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(configuration["Jwt:SecurityKey"])),
ValidateIssuer = false,
ValidateAudience = false,
ClockSkew = TimeSpan.Zero,
};
})
It'll get like this:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(options => { configuration.Bind("AzureAd", options); options.SaveTokens = true; })
.EnableTokenAcquisitionToCallDownstreamApi(scopes)
.AddInMemoryTokenCaches();
Cleared the cookies. Ran the project, clicked on Login button, all ok. But when I click on Get Token
button, I get error 500
with message:
System.InvalidOperationException: No authenticationScheme was specified, and there was no DefaultChallengeScheme found. The default schemes can be set using either AddAuthentication(string defaultScheme) or AddAuthentication(Action<AuthenticationOptions> configureOptions).
at Microsoft.AspNetCore.Authentication.AuthenticationService.ChallengeAsync(HttpContext context, String scheme, AuthenticationProperties properties)
at Microsoft.AspNetCore.Authorization.Policy.AuthorizationMiddlewareResultHandler.HandleAsync(RequestDelegate next, HttpContext context, AuthorizationPolicy policy, PolicyAuthorizationResult authorizeResult)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
I would guess that the server doesn't know how to decode my Bearer tokens created at CreateToken
in my AccountController.cs
file.
What am I'm missing here? Did you run my repro?
I updated the repro GitHub project, please fetch the last version.
I have an update. I could make it run and get token successfully with this:
builder.Services
.AddMicrosoftIdentityWebAppAuthentication(configuration)
.EnableTokenAcquisitionToCallDownstreamApi(scopes)
.AddInMemoryTokenCaches();
But I have a custom claim and a button Get Custom Claim
that when clicked, was expected to get its value. Only the Microsoft Identity's claims are available in my controller and now my Bearer authentication header makes no difference when calling the controllers.
How can I get my custom claims using a token created by my server?
Thanks!
I think I figured out after a lot of trial and error. I found it quite complicated and was almost quitting and implementing my own ITokenAcquisition
.
This is how I registered my services:
// This must be first
builder.Services
.AddMicrosoftIdentityWebAppAuthentication(configuration)
.EnableTokenAcquisitionToCallDownstreamApi(scopes)
.AddInMemoryTokenCaches();
// Then, register JWT Authentication
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters()
{
NameClaimType = "sub",
RoleClaimType = "role",
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(configuration["Jwt:SecurityKey"])),
ValidateIssuer = false,
ValidateAudience = false,
ClockSkew = TimeSpan.Zero,
};
});
In you controller, if you use your ITokenAcquisition
like this:
var token = await _tokenAcquisition.GetAccessTokenForUserAsync(scopes);
, you'll get the error IDW10503: Cannot determine the cloud Instance. The provided authentication scheme was ''. Microsoft.Identity.Web inferred 'Bearer' as the authentication scheme. Available authentication schemes are 'Cookies,OpenIdConnect,Bearer'. See https://aka.ms/id-web/authSchemes
The correct way to make the call above is:
var token = await _tokenAcquisition.GetAccessTokenForUserAsync(scopes: scopes, authenticationScheme: OpenIdConnectDefaults.AuthenticationScheme);
With that, this problem is solved.
@jmprieur If my solution is alright, we can close this topic. Is this solution ok?
Also, there is something to fix in the documentation: the link https://aka.ms/id-web/authSchemes shown in the error IDW10503
doesn't seem to exist.
@FelipeCostaGualberto yes, your solution is right. I had not understood that your web app part was creating a token (not AAD). This makes sense. Since this is the web app, the authentication scheme should be OpenIdConnect indeed.
Thanks for the heads-up for the broken aka.ms link. I just fixed it: https://aka.ms/id-web/authSchemes I also added more info about the error and how to fix it.
Thanks again, and sorry for the pain!
Microsoft.Identity.Web Library
Microsoft.Identity.Web
Microsoft.Identity.Web version
1.25.1
Web app
Sign-in users and call web APIs
Web API
Protected web APIs call downstream web APIs
Token cache serialization
In-memory caches
Description
I get the error
IDW10503
when I try usingITokenAcquisition.GetAccessTokenForUserAsync
method in my controller. I didn't find any documentation about this error. If I downgrade the version of Identity package, it works (quite) as expected.The architecture of my solution is: -Blazor WebAssembly hosted with Asp.Net 6. -Azure OpenId Connect (Microsoft Identity) to authenticate. -JWT is the default Authenticate Scheme. -All using latest stable version.
In the real scenario, my application support both Oidc and User/Password authentication, that's why I need both schemes.
Reproduction steps
There is a repro here: https://github.com/FelipeCostaGualberto/bug-obo-token
First, create an Azure Application with scopes
https://analysis.windows.net/powerbi/api/.default offline_access
. Then, set the values in theappSettings.json
and runExampleObo.Server
project.With the web application provided running, click in the
Login
button. Enter your credentials. You'll get back to the home page. Then, clickGet Token
button.Error message
When I click in the button mentioned above, I get the error:
IDW10503: Cannot determine the cloud Instance. The provided authentication scheme was ''. Microsoft.Identity.Web inferred 'Bearer' as the authentication scheme. Available authentication schemes are 'Bearer,Cookies,OpenIdConnect'. See https://aka.ms/id-web/authSchemes.
The link provided by this error message seems to not exist.
Id Web logs
No response
Relevant code snippets
There is a repro here: https://github.com/FelipeCostaGualberto/bug-obo-token
The most important files in this repo are
ExampleObo.Server\Program.cs
where I set up services andExampleObo.Server\Controller\IndexController.cs
where I have this method to get the desired token:Also
ExampleObo.Server\Controller\AccountController.cs
Is important. Notice that I'm storing user'sEmail
,Utid
andUid
to callITokenAcquisition.GetAccessTokenForUserAsync
.Regression
1.16.0
Expected behavior
The expected behavior when clicking on
Get Token
is to get the token generated byITokenAcquisition.GetAccessTokenForUserAsync
in the body of the page in green color.As you can see, I'm using both packages below:
If I downgrade to
1.16.0
both packages, clear cookies (this is important!) and the login again, theGet Token
will work.Even with this workaround, I'm facing another problem: after some hours with the application running, it seems the Azure Oidc token saved in the token service expires and I begin to get the
MsalUiRequiredException
exception when I click on theGet Token
button again. I need the token to get refreshed because there is a DAX (Power BI) running every 48h on behalf of each user that logins in our websiteAdditional info: the last version that it works is
1.16.0
. I tried using1.16.1
and I also get an error, but an error different from1.25.1
.