Jwt token authorization not working
See original GitHub issueDescribe the bug Authorize directive not working with JWT
To Reproduce Steps to reproduce the behavior:
public void ConfigureServices(IServiceCollection services)
{
var jwtSettings = new JwtSettings();
Configuration.Bind(nameof(JwtSettings), jwtSettings);
services.AddSingleton<IJwtSettings>(jwtSettings);
services.AddIdentity<NZUser, NZRole>()
.AddEntityFrameworkStores<NomadZeteticDbContext>()
.AddDefaultUI()
.AddDefaultTokenProviders();
var key = Encoding.ASCII.GetBytes(jwtSettings.Secret);
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(x =>
{
x.RequireHttpsMetadata = false;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false
};
});
services.AddDbContext<NomadZeteticDbContext>(options =>
{
options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection"), builder =>
{
builder.MigrationsAssembly("NomadZetetic.Data");
});
});
services.Configure<IdentityOptions>(options =>
{
options.Password.RequireDigit = true;
options.Password.RequireLowercase = true;
options.Password.RequireNonAlphanumeric = true;
options.Password.RequireUppercase = true;
options.Password.RequiredLength = 6;
options.Password.RequiredUniqueChars = 1;
});
services.AddScoped<IUserService, UserService>();
services.AddGraphQL(GraphQL.Builder.BuildSchema);
services.AddMvc();
}
public static class Builder
{
public static ISchema BuildSchema(IServiceProvider serviceProvider)
{
return SchemaBuilder.New()
.AddServices(serviceProvider)
.AddAuthorizeDirectiveType()
.AddType<UserType>()
.AddType<SignInResponseType>()
.AddQueryType<QueryType>()
.Create();
}
}
public class UserService : IUserService
{
private readonly IJwtSettings jwtSettings;
private readonly NomadZeteticDbContext dbContext;
public UserService(NomadZeteticDbContext dbContext, IJwtSettings jwtSettings)
{
this.dbContext = dbContext;
this.jwtSettings = jwtSettings;
}
public async Task<ISignInResponse> SignIn(string email, string password)
{
var passwordHasher = new PasswordHasher<NZUser>();
var user = await dbContext.Users.SingleOrDefaultAsync(q => q.Email == email).ConfigureAwait(false);
if (user == null)
{
throw new AuthenticationException("User not found");
}
var passwordVerificationResult = passwordHasher.VerifyHashedPassword(user, user.PasswordHash, password);
if (passwordVerificationResult != PasswordVerificationResult.Success)
{
throw new AuthenticationException("Invalid password");
}
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(jwtSettings.Secret);
var tokenDescriptor = new SecurityTokenDescriptor
{
Issuer = jwtSettings.Issuer,
Audience = jwtSettings.Audience,
IssuedAt = DateTime.Now,
Subject = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.Name, user.Id.ToString())
}),
Expires = DateTime.UtcNow.AddDays(7),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var accessToken = tokenHandler.WriteToken(token);
return new SignInReponse { AccessToken = accessToken };
}
public async Task<INZUser> GetUserById(string userId)
{
return await dbContext.Users.SingleAsync(u => u.Id == Guid.Parse(userId));
}
}
public class Query
{
private readonly IUserService userService;
public Query(IUserService userService)
{
this.userService = userService;
}
public async Task<ISignInResponse> SignIn(string email, string password)
{
return await userService.SignIn(email, password);
}
public async Task<INZUser> Me()
{
return await userService.GetUserById("aa"); // this just for test - i want to see an error
}
}
public class QueryType : ObjectType<Query>
{
protected override void Configure(IObjectTypeDescriptor<Query> descriptor)
{
descriptor.Field(t => t.SignIn(default, default))
.Argument("email", a => a.Type<NonNullType<StringType>>())
.Argument("password", a => a.Type<NonNullType<StringType>>())
.Type<NonNullType<SignInResponseType>>();
descriptor.Field(t => t.Me())
.Authorize()
.Type<NonNullType<UserType>>();
}
}
public class SignInResponseType : ObjectType<ISignInReponse>
{
protected override void Configure(IObjectTypeDescriptor<ISignInReponse> descriptor)
{
descriptor.Field(t => t.AccessToken)
.Type<NonNullType<StringType>>();
}
}
public class UserType : ObjectType<INZUser>
{
protected override void Configure(IObjectTypeDescriptor<INZUser> descriptor)
{
descriptor.Name("User");
descriptor.Field(t => t.Id).Type<NonNullType<StringType>>();
descriptor.Field(t => t.UserName).Type<NonNullType<StringType>>();
}
}
That’s what i got.
All working with classical [Authorize] attribute for built in classical controllers. But for graphql it’s not working. Maybe exist other way to authorize user with JWT token via middleware (if yes could somebody give an example how to do this)?
Expected behavior
Should throw an error…
Desktop (please complete the following information):
- OS: MacOS (asp.net core 2.2)
- Version Latest
Issue Analytics
- State:
- Created 4 years ago
- Comments:5 (4 by maintainers)
Top Results From Across the Web
Jwt tokens authorization is not working
I ran into a similar issue when I setup JWT and kept getting 401s. Try changing the order in your startup class so...
Read more >Troubleshooting JWT authentication
JWT tokens are NOT presented in an HTTP Authorization header. A JWT is not itself a way to authenticate to the API. Instead,...
Read more >The auth is not working in .net core web api?
For example, if using JWT, ensure that the token is being passed in the "Authorization" header with the "Bearer " prefix. Check the ......
Read more >ASP.NET Core Web API: Troubleshooting
1. Are you passing the JWT in the Authorization header? ... Check if you are passing the JWT as a Bearer token in...
Read more >Troubleshooting JwtBearer authentication problems in ASP ...
This error is typically generated by the JwtBearer handler, and it means that the incoming token is not found, valid or accepted. 403...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
After looking at you repro I saw that the middleware order was not correct:
The middleware is like a pipeline where the request is handled by each middleware. Since authentication is coming after GraphQL the authentication middleware is never able to handle the request.
A correct order would look like the following:
Thanks men, I faced a similar situation and your answer reminds me that I forget to add
UseAuthentication
inapp
. Cheers men, you saved my day =]