In a normal authentication with JWT the token will be in the “Auth header” of the request and the authentication will take place as explained here
ASP.NET Core Authentication with JWT and Angular - Part 1
Securing a web application is one of the most important to do and usually one of the hardest things to pull off. In this series, we are going tolearn how to implement authentication with Angular on the front end side and ASP.Net Core on the server side using the JSON web tokens (JWT).
But in case you need to authorize your requests with JWT token while the token is in the URL like this:
https://localhost:444/controller/action?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3VzZXJkYXRhIjoie1widXNlcm5hbWVcIjpcInRlYWNoZXJAa28uY29tXCIsXCJwZWVyVXNlck5hbWVcIjpcInN0dWRlbnRAa28uY29tXCIsXCJwbGF0Zm9ybUlkXCI6MCxcInRlbmFudElkXCI6XCI4M0IwM0RCQi0xQTEyLTQwQ0YtQjZDRS0wNDQ2RTA5RDFBNjcjZGV2b3AuYWxpQGdtYWlsLmNvbVwiLFwicGVlckRpc3BsYXlOYW1lXCI6XCJUZWFjaGVyIDFcIixcImRpc3BsYXlOYW1lXCI6XCJzdHVkZW50IDFcIixcInJ0Y1VybFwiOlwiaHR0cHM6Ly9sb2NhbGhvc3Q6NDQ0L3dlYnJ0Yy9jYWxsXCIsXCJzZXJ2aWNlVXJsXCI6XCJodHRwczovL1NlcnZpY2UvTG9nL2xvZ1wifSIsImV4cCI6MTU0NzgxNzcxMiwiaXNzIjoiaHR0cHM6Ly9sb2NhbGhvc3Q6NDQ0IiwiYXVkIjoiaHR0cHM6Ly9sb2NhbGhvc3Q6NDQ0In0.
DUzq0Im1nXLdGtZVI389NhuMXDe0YkGpZJTvOHytOoQ
things will get a bit tricky. so I decided to make a quick tutorial to explain how I managed to implement it.
In a Nutshell
so let’s get to it :) your ConfigureServices method will be something like this :
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
and your Configure method:
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
app.UseHttpsRedirection();
}
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMiddleware(typeof(AuthorizationMiddleware));
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
the magic will happen in
app.UseMiddleware(typeof(AuthorizationMiddleware));
Let’s have look at AuthorizationMiddleware’s invoke method in detail:
public async Task InvokeAsync(HttpContext context)
{
//getting the token from the URL
var queryString = HttpUtility.ParseQueryString(context.Request.QueryString.Value);
//setting the validation parameters
//warning : these parameters should be same with the token's issuer parameters
var validationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = _settings.Value.Jwt_valid_issuer,
ValidAudience = _settings.Value.Jwt_valid_audience,
IssuerSigningKey =
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_settings.Value.Jwt_issuer_key))
};
var validator = new JwtSecurityTokenHandler();
if (!validator.CanReadToken(queryString.Get("token")))
throw new UnauthorizedAccessException("token is not readable");
try
{
//trying to parse the token
var principal =
validator.ValidateToken(queryString.Get("token"), validationParameters, out var validatedToken);
if (principal.HasClaim(c => c.Type == ClaimTypes.UserData))
{
var userData = principal.Claims.First(c => c.Type == ClaimTypes.UserData).Value;
//setting AuthData to be used for later usages in other middlewares
//as well as the controller which is in the MVC middleware
context.Items["AuthData"] = JsonConvert.DeserializeObject<LoginModel>(userData);
//authorizing the http context
context.User.AddIdentity((ClaimsIdentity) principal.Identity);
//invoking the next middleware
await _next.Invoke(context);
}
}
catch (Exception e)
{
throw;
}
}
therefore if this Middleware reaches the
await _next.Invoke(context);
it means that the token is valid and the HttpContext is authorized plus we have added the parsed version of the token to the HttpContext
context.Items["AuthData"] = JsonConvert.DeserializeObject<LoginModel>(userData);
So you can implement your controller like you have used the default JwtBearer authentication:
[HttpGet,Authorize]
public IActionResult Action()
{
//retrieve the parsed token
var loginModel = HttpContext.Items["AuthData"] as LoginModel;
return View(loginModel?.Username);
}
Let me know if you had any questions & have fun coding :)