I have an API that is using a ASP.NET Core Identity and JWT tokens. The application is only using the Identity system to manager users (adding, removing and updating passwords & profile data), not to do any kind authentication (that is handled externally). I am now trying to port this application from ASP.NET Core 1.x to 2.0 and running into problems. Prior to 2.0 I could call services.AddIdentity(/* options */) to add all of the required services and not call app.UseIdentity() so that the cookie middleware was not added.
This solution was referenced in an issue awhile ago: https://github.com/aspnet/Security/issues/804
In 2.0 calling services.AddIdentity always adds cookie authentication which then takes over the authentication pipeline and will redirect unauthenticated requests to the login page instead of returning a 401. Even trying to override the cookie authentication by using the following after AddIdentity is called does not work:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
{
options.Audience = "my_aud";
options.Authority = "my_authority";
});
Is there anyway to add the Identity management services to the DI container without dragging along the cookie middleware?
I am also having this issue and the AddIdentityCore() didn't work for me.
Any other way to make this work?
Use the following configuration for Asp.net core 2.0
set the DefaultAuthenticateScheme and DefaultChallengeScheme in AddAuthentication method.
IConfigurationSection jwtAppSettingOptions = Configuration.GetSection(nameof(JwtIssuerOptions));
TokenValidationParameters tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = "issuer",
ValidateAudience = true,
ValidAudience = "audience",
ValidateIssuerSigningKey = true,
IssuerSigningKey = _signingKey,
RequireExpirationTime = false,
ValidateLifetime = false,
ClockSkew = TimeSpan.Zero
};
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}) .AddJwtBearer(options => {
options.TokenValidationParameters = tokenValidationParameters
});
Thanks @HaoK & @sriram5052 , I think AddIdentityCore does solve my issue, my only lingering concern is discover-ability of this API. I haven't see it documented anywhere and its implemented in a completely different assembly from the rest of the identity related configuration stuff so it is difficult to find.
Yup its a future building block at this point, but it is the more granular way to add identity that you are looking for
When I'm using services.AddIdentityCore<ApplicationUser>(setupAction: null) I get the following exception:
The number of generic arguments provided doesn't equal the arity of the generic type definition.
Parameter name: instantiation
I think this is because IdentityBuilder needs the TRole type but the extension AddIdentityCore doesn't allow to specify it
What am I missing?
PS. I know this issue is closed, should I open a new one?
Thank you
@isaacOjeda I ran into the same problem and resolved it by just instantiating a new IdentityBuilder that specifies the roles type:
C#
IdentityBuilder builder = services.AddIdentityCore<User>(/* options */);
builder = new IdentityBuilder(builder.UserType, typeof(IdentityRole), builder.Services);
return builder.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
In addition, if we want to use RoleManager
services.AddScoped<IRoleValidator<IdentityRole>, RoleValidator<IdentityRole>>();
services.AddScoped<RoleManager<IdentityRole>, RoleManager<IdentityRole>>();
// or
builder.AddRoleValidator<RoleValidator<Role>>();
builder.AddRoleManager<RoleManager<Role>>();
@HaoK I think that it would be nice to have extension method like AddIdentityCore<TUser, TRole> (in 2.1.0 maybe?).
Hi, I know this is closed but I'm getting this error:
InvalidOperationException: No IAuthenticationSignInHandler is configured to handle sign in for the scheme: Identity.Application
Microsoft.AspNetCore.Authentication.AuthenticationService+<SignInAsync>d__13.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Identity.SignInManager+<SignInAsync>d__30.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Identity.SignInManager+<SignInOrTwoFactorAsync>d__52.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.AspNetCore.Identity.SignInManager+<PasswordSignInAsync>d__33.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.AspNetCore.Identity.SignInManager+<PasswordSignInAsync>d__34.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
this is my configuration:
```
Configuration.GetSection(nameof(CustomIdentityOptions)).Bind(identityOptions);
IdentityBuilder builder = services.AddIdentityCore
{
// ...
});
builder = new IdentityBuilder(builder.UserType, typeof(Role), builder.Services)
.AddDefaultTokenProviders();
builder.AddSignInManager<SignInManager<User>>();
builder.AddRoleValidator<RoleValidator<Role>>();
builder.AddRoleManager<RoleManager<Role>>();
builder.AddEntityFrameworkStores<MyDbContext>();
```
I had exactly this problem - trying to use Identity to just manage users, passwords etc. and JWT for Auth. I'm writing a pure Web API with no front end code so I didn't want the cookie auth stuff.
What I've found works from a functional perspective is to revert to using
services.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<MyContext>();
But you must ensure this is added _before_ the jwt auth stuff:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters =
new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = "...",
ValidAudience = "...",
IssuerSigningKey = "...."
};
});
if the identity stuff is added afterwards, it still breaks the authorization, but this way around appears to work. It still creates a cookie, but from what I can tell (from admittedly fairly limited testing) it is not using this for authentication, only the bearer token. YMMV but I've wasted a huge amount of time already on this so I'll settle for that for the moment.
Given the trumping about how amazingly modular and granular .Net Core is, I'm rather surprised that trying to get _just_ the user storage, hashing, password complexity etc. stuff _without_ also adding token authorisation is so hard. AddIdentityCore<> looks perfect for doing this, but just doesn't seem to do enough for my needs at least.
AHA! Actually, by following the linked issue above:
https://github.com/aspnet/Identity/issues/1423
I've been able to get it to work fine, and STOP SENDING THE DARN COOKIE...
Basically, do this:
IdentityBuilder builder = services.AddIdentityCore<IdentityUser>(opt =>
{
opt.Password.RequireDigit = true;
opt.Password.RequiredLength = 8;
opt.Password.RequireNonAlphanumeric = false;
opt.Password.RequireUppercase = true;
opt.Password.RequireLowercase = true;
}
);
builder = new IdentityBuilder(builder.UserType, typeof(IdentityRole), builder.Services);
builder
.AddEntityFrameworkStores<MyContext>();
builder.AddRoleValidator<RoleValidator<IdentityRole>>();
builder.AddRoleManager<RoleManager<IdentityRole>>();
builder.AddSignInManager<SignInManager<IdentityUser>>();
And then when authenticating a username/password, you use CheckPasswordSignInAsync rather than PasswordSignInAsync:
//find user first...
var user = await _userManager.FindByNameAsync(userName);
if (user == null)
{
return null;
}
//validate password...
var signInResult = await _signInManager.CheckPasswordSignInAsync(user, password, false);
if (signInResult.Succeeded)
{
...do stuff
}
And then everything seems to work.... no stupid cookie. :)
I've tried to move from services.AddIdentity<User, Role> to services.AddIdentityCore<User>, because the first one didn't allow me to use JWT.
IdentityBuilder builder = services.AddIdentityCore<IdentityUser>(options => {});
builder = new IdentityBuilder(builder.UserType, typeof(IdentityRole), builder.Services);
builder.AddRoleManager<RoleManager<IdentityRole>>();
builder.AddSignInManager<SignInManager<IdentityUser>>();
builder.AddEntityFrameworkStores<DBContext>();
builder.AddDefaultTokenProviders();
SignInManager.PasswordSignInAsync and SignInManager.SignInAsync were producing errors No IAuthenticationSignInHandler is configured to handle sign in for the scheme: Identity.Application
So, I changed them to the SignInManager.CheckPasswordSignInAsync - and it worked like a charm. In my case, it was the right decision because my WebApi needs simply to check the password and send the token back.
@allownulls - yes. I had all the same issues. I did in fact ask this on SO (and ended up answering it myself)
https://stackoverflow.com/questions/46323844/net-core-2-0-web-api-using-jwt-adding-identity-breaks-the-jwt-authentication
Most helpful comment
AHA! Actually, by following the linked issue above:
https://github.com/aspnet/Identity/issues/1423
I've been able to get it to work fine, and STOP SENDING THE DARN COOKIE...
Basically, do this:
And then when authenticating a username/password, you use
CheckPasswordSignInAsyncrather thanPasswordSignInAsync:And then everything seems to work.... no stupid cookie. :)