ASP.NET Core Custom authorization handler not triggering - c#

I am trying to setup a custom authorization handler in my project closely following the Resource-based authorization in ASP.NET Core Microsoft documentation. However, calling the API endpoint always returns a 403 response and doesn't even trigger a breakpoint in my handler.
Feels like I quadruple checked every single thing yet it still doesn't work. Am I blind or is there something wrong with my code?
Here's my custom handler:
public class TripAuthorizationHandler : AuthorizationHandler<SameUserRequirement, Trip>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, SameUserRequirement requirement, Trip resource)
{
if(context.User.FindFirst("userId").Value == resource.ApplicationUserId)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
public class SameUserRequirement : IAuthorizationRequirement{}
Program.cs file:
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = builder.Configuration["JWT:Issuer"],
ValidAudience = builder.Configuration["JWT:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["JWT:Key"]))
};
});
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("SameUser", policy => policy.Requirements.Add(new SameUserRequirement()));
});
builder.Services.AddTransient<IAuthorizationHandler, TripAuthorizationHandler>();
builder.Services.AddTransient<IAuthenticationService, AuthenticationService>();
builder.Services.AddTransient<ITokenService, TokenService>();
builder.Services.AddAutoMapper(typeof(Program));
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseMiddleware<ExceptionHandlingMiddleware>();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
And here's the controller:
[Authorize(Policy = "SameUser")]
[HttpPut("trips/{tripId}")]
public async Task<IActionResult> UpdateTrip([FromBody] TripPostDto request, int tripId)
{
var trip = await _tripService.GetByIdAsync(tripId);
var authorizationResult = await _authorizationService.AuthorizeAsync(User, trip, "SameUser");
if (authorizationResult.Succeeded)
{
await _tripService.UpdateAsync(tripId, request);
return NoContent();
}
else if (User.Identity.IsAuthenticated)
{
return Forbid();
}
else
{
return Challenge();
}
}
Edit:
Here's my implementation of AuthenticationService
public class AuthenticationService : IAuthenticationService
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly ITokenService _tokenService;
private readonly IMapper _mapper;
public AuthenticationService(UserManager<ApplicationUser> userManager, IMapper mapper, ITokenService tokenService)
{
_userManager = userManager;
_mapper = mapper;
_tokenService = tokenService;
}
public async Task<SuccessfulLoginDto> LoginAsync(LoginUserDto loginUserDto)
{
var user = await _userManager.FindByEmailAsync(loginUserDto.Email);
if(user == null)
{
throw new ValidationException("Invalid login data!");
}
var passwordValid = await _userManager.CheckPasswordAsync(user, loginUserDto.Password);
if (!passwordValid)
{
throw new ValidationException("Invalid login data!");
}
var accessToken = await _tokenService.GetTokenAsync(user);
return new SuccessfulLoginDto() { Token = accessToken.AccessToken };
}
public async Task RegisterAsync(RegisterUserDto registerUserDto)
{
var existingUser = await _userManager.FindByEmailAsync(registerUserDto.Email);
if (existingUser != null)
{
throw new UserAlreadyExistsException("User with this email already exists!");
}
var newUser = _mapper.Map<ApplicationUser>(registerUserDto);
var result = await _userManager.CreateAsync(newUser, registerUserDto.Password);
if (!result.Succeeded)
{
throw new ValidationException(string.Join(" ", result.Errors.Select(e => e.Description)));
}
await _userManager.AddToRoleAsync(newUser, Authorization.Roles.User.ToString());
}
}

Have you tried ordering the service injection before?
Order matters in Startup
builder.Services.AddTransient<IAuthorizationHandler, TripAuthorizationHandler>();
builder.Services.AddTransient<IAuthenticationService, AuthenticationService>();
builder.Services.AddTransient<ITokenService, TokenService>();
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = builder.Configuration["JWT:Issuer"],
ValidAudience = builder.Configuration["JWT:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["JWT:Key"]))
};
});
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("SameUser", policy => policy.Requirements.Add(new SameUserRequirement()));
});

Related

Reloading page affecting sign out of user/log out

I have been trying to getting this fixed for many times already, but have no success so far. I am logging into my page and everything works fine. However every time I am reloading my page I am ending up signed out and redirected to "Login page" and have to sign in again. What is the problem? Is there is something messed up with my Coockie logic?
I have also tried to implement login.RememberMe logic, but it does not work either. I have checked that login.RememberMe returns true, but no effect.
Login method in controller:
[HttpPost]
public async Task<IActionResult> Login([FromBody] LoginModel login)
{
ApplicationUser user = await this.SignInManager.UserManager.FindByEmailAsync(login.Email);
Microsoft.AspNetCore.Identity.SignInResult result =
await this.SignInManager.PasswordSignInAsync(login.Email, login.Password, login.RememberMe, false);
if (!result.Succeeded)
{
List<string> errors = new List<string>();
errors.Add("Email and password are invalid.");
return BadRequest(new LoginResult
{
Successful = false,
Errors = errors,
});
}
IList<string> roles = await this.SignInManager.UserManager.GetRolesAsync(user);
List<Claim> claims = new List<Claim>
{
new Claim(ClaimTypes.Name, login.Email)
};
ClaimsIdentity identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
ClaimsPrincipal principal = new ClaimsPrincipal(identity);
AuthenticationProperties props = new AuthenticationProperties
{
IsPersistent = true,
ExpiresUtc = DateTime.UtcNow.AddMonths(1)
};
// to register the cookie to the browser
this.HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal, props).Wait();
foreach (string role in roles)
{
claims.Add(new Claim(ClaimTypes.Role, role));
}
SymmetricSecurityKey key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(this.Configuration["JwtSecurityKey"]));
SigningCredentials creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
DateTime expiry = DateTime.Now.AddDays(Convert.ToInt32(this.Configuration["JwtExpiryInDays"]));
JwtSecurityToken token = new JwtSecurityToken(
this.Configuration["JwtIssuer"],
this.Configuration["JwtAudience"],
claims,
expires: expiry,
signingCredentials: creds
);
return Ok(new LoginResult
{
Successful = true,
Token = new JwtSecurityTokenHandler().WriteToken(token),
});
}
Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["JwtIssuer"],
ValidAudience = Configuration["JwtAudience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JwtSecurityKey"]))
};
})
.AddCookie(options =>
{
options.Cookie.Name = "DashCoockie";
options.LoginPath = "/login";
options.ExpireTimeSpan = TimeSpan.FromDays(30);
options.SlidingExpiration = true;
options.EventsType = typeof(CookieAuthEvent);
});
services.AddScoped<CookieAuthEvent>();
services.AddAuthorization(config =>
{
config.AddPolicy(Policies.IsAdmin, Policies.IsAdminPolicy());
config.AddPolicy(Policies.IsUser, Policies.IsUserPolicy());
});
services.ConfigureApplicationCookie(options =>
{
options.Cookie.HttpOnly = true;
options.Events.OnRedirectToLogin = context =>
{
context.Response.StatusCode = 401;
return Task.CompletedTask;
};
});
services.AddControllers();
// Instant update on runtime for development purposes
services.AddControllersWithViews().AddRazorRuntimeCompilation();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseAuthentication();
app.UseAuthorization();
app.UseCookiePolicy();
}
CookieAuthEvent.cs:
public class CookieAuthEvent : CookieAuthenticationEvents
{
public override async Task ValidatePrincipal(CookieValidatePrincipalContext context)
{
context.Request.HttpContext.Items.Add("ExpiresUTC", context.Properties.ExpiresUtc);
}
}
After logging in (Coockie name is the same, just hided first part as it is in the code above):
My project structure is as follows: Client, Server, Shared. I found solution by using LocalStorage and AuthService : IAuthService on Client side. So is it so that in my setup the only solution is to use LocalStorage?
public class AuthService : IAuthService
{
private readonly HttpClient _httpClient;
private readonly AuthenticationStateProvider _authenticationStateProvider;
private readonly ILocalStorageService _localStorage;
public AuthService(HttpClient httpClient,
AuthenticationStateProvider authenticationStateProvider,
ILocalStorageService localStorage)
{
_httpClient = httpClient;
_authenticationStateProvider = authenticationStateProvider;
_localStorage = localStorage;
}
public async Task<RegisterResult> Register(RegisterModel registerModel)
{
var result = await _httpClient.PostJsonAsync<RegisterResult>("api/accounts", registerModel);
return result;
}
public async Task<LoginResult> Login(LoginModel loginModel)
{
var loginAsJson = JsonSerializer.Serialize(loginModel);
var response = await _httpClient.PostAsync("api/Login", new StringContent(loginAsJson, Encoding.UTF8, "application/json"));
var loginResult = JsonSerializer.Deserialize<LoginResult>(await response.Content.ReadAsStringAsync(), new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
if (!response.IsSuccessStatusCode)
{
return loginResult;
}
await _localStorage.SetItemAsync("authToken", loginResult.Token);
((ApiAuthenticationStateProvider)_authenticationStateProvider).MarkUserAsAuthenticated(loginModel.Email);
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", loginResult.Token);
return loginResult;
}
public async Task Logout()
{
await _localStorage.RemoveItemAsync("authToken");
((ApiAuthenticationStateProvider)_authenticationStateProvider).MarkUserAsLoggedOut();
_httpClient.DefaultRequestHeaders.Authorization = null;
}
}
It seems that you didn't set the token in your request header
try add these codes in your startup class:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Events = new JwtBearerEvents()
{
OnMessageReceived = context =>
{
context.Token = context.Request.Cookies["access_token"];
return Task.CompletedTask;
}
};
});
In your Login Action :
Response.Cookies.Append("access_token",your JwtSecurityToken)

SignalR authentication issue

Im working on an ASP.NET core app and I need to implements a chat with SignalR.
Im using Identity with jwt to manage login/permissions and this works fine.
I followed this docs for implementing authentication in SignalR hub but it doesn't work, my hub functions can be reached even with the [Authorize] attribute on the hub.
This is my code for configuring the service
services
.AddAuthorization()
.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.RequireHttpsMetadata = false;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = jwtSettings.Issuer,
ValidAudience = jwtSettings.Issuer,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.Secret)),
ClockSkew = TimeSpan.Zero
};
options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
var accessToken = context.Request.Query["access_token"];
// If the request is for our hub...
var path = context.HttpContext.Request.Path;
if (!string.IsNullOrEmpty(accessToken) && (path.StartsWithSegments("/chat")))
{
// Read the token out of the query string
context.Token = accessToken;
}
return Task.CompletedTask;
}
};
});
And this is the code I have for my hub
[Authorize]
public class Chat : Hub<IChatClientMethods>
{
private readonly ProjectHubContext _context;
private readonly UserManager<User> _userManager;
public Chat(ProjectHubContext context, UserManager<User> userManager) : base()
{
_context = context;
_userManager = userManager;
}
// This method is executed even with the [Authorize] attribute
public override async Task OnConnectedAsync()
{
await base.OnConnectedAsync();
Console.WriteLine("Connected");
var user = await _userManager.GetUserAsync(Context.User); //Always null
}
}
And finnaly the hub mapping
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHub<Chat>("/chat");
});
Why can I call hub functions from client when I provide a random test token ?
I found out why my [Authorize] tag didn't work.
I used a wrong using.
I used using MiNET.Plugins.Attributes;
instead of using Microsoft.AspNetCore.Authorization;

Net Core 2.1 Bearer was not authenticated error in Controller

I am getting an error in net core 2.1:
Bearer was not authenticated.
Failure message: No SecurityTokenValidator available for token: null
The asp net output window is:
info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[7]
Bearer was not authenticated. Failure message: No SecurityTokenValidator available for token: null
info: Microsoft.AspNetCore.Cors.Infrastructure.CorsService[4]
Policy execution successful.
The accounts controller code is here:
namespace quiz_backend.Controllers
{
public class Credentials
{
public string Email { get; set; }
public string Password { get; set; }
}
[Produces("application/json")]
[Route("api/Account")]
public class AccountController : Controller
{
readonly UserManager<IdentityUser> userManager;
readonly SignInManager<IdentityUser> signInManager;
public AccountController(UserManager<IdentityUser> userManager, SignInManager<IdentityUser> signInManager)
{
this.userManager = userManager;
this.signInManager = signInManager;
}
[HttpPost]
public async Task<IActionResult> Register([FromBody] Credentials credentials)
{
var user = new IdentityUser {
UserName = credentials.Email,
Email = credentials.Email
};
var result = await userManager.CreateAsync(user, credentials.Password);
if (!result.Succeeded)
return BadRequest(result.Errors);
await signInManager.SignInAsync(user, isPersistent: false);
// create a token
var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("this is the secret phrase"));
var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);
var jwt = new JwtSecurityToken(signingCredentials: signingCredentials);
return Ok(new JwtSecurityTokenHandler().WriteToken(jwt));
}
}
}
Here is the startup.cs
namespace quiz_backend
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options => options.AddPolicy("Cors", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
}));
services.AddDbContext<QuizContext>(opt =>opt.UseInMemoryDatabase("quiz"));
services.AddDbContext<UserDbContext>(opt => opt.UseInMemoryDatabase("user"));
services.AddIdentity<IdentityUser, IdentityRole>().AddEntityFrameworkStores<UserDbContext>();
var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("this is the secret phrase"));
services.AddAuthentication(options =>{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(cfg => {
cfg.RequireHttpsMetadata = false;
cfg.SaveToken = true;
cfg.TokenValidationParameters = new TokenValidationParameters()
{
IssuerSigningKey = signingKey,
ValidateAudience = false,
ValidateLifetime = false,
ValidateIssuerSigningKey = true
};
});
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseAuthentication();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors("Cors");
app.UseMvc();
}
}
}
This is the front end auth code to attach the token to the header in ts:
export class AuthInterceptor implements HttpInterceptor {
constructor() {}
intercept(req, next) {
var token = localStorage.getItem('token')
var authRequest = req.clone({
headers: req.headers.set('Authorization', `Bearer ${token}`)
})
return next.handle(authRequest)
}
}
Based on your code, it seems that the issue is that the token received is not valid (NULL).
Failure message: No SecurityTokenValidator available for token: null
First of all, you should make sure the token arrives as expected.

SignalR ASP.NET Core 2 context.Token set but not working

I'm trying to implement jwt token in a signalr logger hub.
But somehow I keep getting an Unauthorized response
JS
let url = '/hub/log?token='+getToken();
let http = new this.$signalR.HttpConnection(url, options);
this.connection = new this.$signalR.HubConnection(http);
C# ConfigureServices
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Events = new JwtBearerEvents()
{
OnMessageReceived = context =>
{
if (context.Request.Path.ToString().StartsWith("/hub/"))
{
context.Token = context.Request.Query["token"];
}
return Task.CompletedTask;
}
};
options.TokenValidationParameters =
new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = settings.JwtValidIssuer,
ValidAudience = settings.JwtValidAudience,
IssuerSigningKey = JwtSecurityKey.Create(settings.JwtSecurityKey)
};
});
The debugger is breaking on
context.Token = context.Request.Query["token"];
and context.Token is set
C# Hub
[Authorize(Roles = "Admin")]
public class LoggerHub : Hub
{
private readonly IServerManager serverManager;
public LoggerHub(IServerManager serverManager)
{
this.serverManager = serverManager;
}
[Authorize(Roles = "Admin")]
public override Task OnConnectedAsync()
{
serverManager.Logger.Log(Shared.Logging.LogLevel.Info, "New websocket connection");
return base.OnConnectedAsync();
}
public override Task OnDisconnectedAsync(Exception exception)
{
serverManager.Logger.Log(Shared.Logging.LogLevel.Info, "a Socket disconnected");
return base.OnDisconnectedAsync(exception);
}
}
What am i doing wrong?
thanks in advance
Personnaly I check the request type like that before set the token
o.Events = new JwtBearerEvents //For signalR
{
OnMessageReceived = context =>
{
if (context.HttpContext.WebSockets.IsWebSocketRequest || context.Request.Headers["Accept"] == "text/event-stream")
{
StringValues accessToken = context.Request.Query["token"];
if (!string.IsNullOrEmpty(accessToken))
context.Token = accessToken;
}
return Task.CompletedTask;
}
};

How to authorize in ASP.NET Core 2 using jwt

I'm using the [Authorize] attribute for authentification in my controller, but when I get a request to TestMethod I get an error: "500 Internal..".
What am I doing wrong??
That my code from StartUp.cs
services.AddAuthorization(options =>
{
options.DefaultPolicy =
new AuthorizationPolicyBuilder("Identity.Application")
.RequireAuthenticatedUser()
.Build();
});
services
.AddAuthentication(option =>
{
option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.RequireHttpsMetadata = false;
options.TokenValidationParameters =
new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
SaveSigninToken = true,
ValidateIssuer = true,
ValidIssuer = "http://blabla/",
ValidateAudience = true,
ValidAudience = "http://blabla/",
ValidateLifetime = true,
IssuerSigningKey = blabla.bla(),
ValidateIssuerSigningKey = true,
};
});
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme);
services.AddMvc();
And also code from Controller
[Route("test"), HttpPost]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public void Test() { }
Do you have ideas?
I'm using these libraries to generate the token:
System.IdentityModel.Tokens.Jwt;
Microsoft.IdentityModel.Tokens;
If you want to use the [Authorize] attribute you need to make a policy:
//new policy makes [Authorize] availible by claims
services.AddAuthorization((options) => {
options.AddPolicy("MyNewPolicy", policybuilder =>
{
policybuilder.RequireAuthenticatedUser();
policybuilder.RequireClaim("role", "someClaim");
});
});
//usage
[Authorize(Roles = "someClaim")]
public async Task<IActionResult> About(){
}
//to awnsr your comment add a list of claims to your user class ex:
new TestUser
{
SubjectId="1001",
Username="Frank",
Password="password",
Claims= new List<Claim>
{
new Claim("given_name","Frank"),
new Claim("family_name","Underwood"),
new Claim("address","1 addy rd unit 233"),
new Claim("role", "someClaim")
}
}
I ran into a lot of issues when tryout out AddJwtBearer. Finally I found out that making a manual login wasn't that much harder, worked easily and is also easier to debug.
Basically, first I created a helper class for creating and validating tokens. Here is the source code for the class: https://github.com/neville-nazerane/netcore-jwt-sample/blob/master/website/TokenGenerator.cs. Everything you had added in your TokenValidationParameters can go inside this class.
Once you have that, here is a Boiler plate authentication scheme:
public class TokenAuthenticationOptions : AuthenticationSchemeOptions
{
}
public class TokenAuthentication : AuthenticationHandler<TokenAuthenticationOptions>
{
public const string SchemeName = "TokenAuth";
public TokenAuthentication(IOptionsMonitor<TokenAuthenticationOptions> options, ILoggerFactory logger,
UrlEncoder encoder, ISystemClock clock)
: base(options, logger, encoder, clock)
{
}
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
return Task.Run(() => Authenticate());
}
private AuthenticateResult Authenticate()
{
string auth, token;
auth = Context.Request.Headers["Authorization"];
if (auth == null) return AuthenticateResult.Fail("No JWT token provided");
var auths = auth.Split(" ");
if (auths[0].ToLower() != "bearer") return AuthenticateResult.Fail("Invalid authentication");
token = auths[1];
try
{
var generator = new TokenGenerator();
var principal = generator.Validate(token);
return AuthenticateResult.Success(new AuthenticationTicket(principal, SchemeName));
}
catch
{
return AuthenticateResult.Fail("Failed to validate token");
}
}
}
Finally, in your start up you can use this scheme this way:
services.AddAuthentication(TokenAuthentication.SchemeName)
.AddScheme<TokenAuthenticationOptions, TokenAuthentication>
(TokenAuthentication.SchemeName, o => { });

Categories