C
C#16mo ago
Scottek utek

✅ jwt authentication always returns 401

I'm trying to build a backend with .net & firebase, but I can not get over one specific problem. When I try to implement jwt, calling any endpoint just throws 401 error code (after logging in in swagger ofc). What am I doing wrong?
24 Replies
Scottek utek
Scottek utek16mo ago
Startup.cs:
public void ConfigureServices(IServiceCollection services) {
...
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = _configuration["Auth:Authority"];
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = _configuration["Auth:Issuer"],
ValidateAudience = true,
ValidAudience = _configuration["Auth:Audience"],
ValidateLifetime = true,
};
});

services.AddAuthorization(options =>
{
options.AddPolicy(
"AdminOnly",
policy => policy.RequireClaim(
"http://schemas.microsoft.com/ws/2008/06/identity/claims/role",
"admin"
)
);
});
...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
...
app.UseStatusCodePages();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseCors();

app.UseEndpoints(endpoints => endpoints.MapControllers());
}
public void ConfigureServices(IServiceCollection services) {
...
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = _configuration["Auth:Authority"];
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = _configuration["Auth:Issuer"],
ValidateAudience = true,
ValidAudience = _configuration["Auth:Audience"],
ValidateLifetime = true,
};
});

services.AddAuthorization(options =>
{
options.AddPolicy(
"AdminOnly",
policy => policy.RequireClaim(
"http://schemas.microsoft.com/ws/2008/06/identity/claims/role",
"admin"
)
);
});
...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
...
app.UseStatusCodePages();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseCors();

app.UseEndpoints(endpoints => endpoints.MapControllers());
}
FirebaseAuthenticationClient.cs:
public class FirebaseAuthenticationClient : IFirebaseAuthenticationClient
{
private readonly string _appKey;
private readonly HttpClient _httpClient;

public FirebaseAuthenticationClient(IConfiguration configuration, HttpClient httpClient)
{
_appKey = configuration.GetValue<string>("FirebaseAppKey");
_httpClient = httpClient;
}
public async Task<Token> Login(string username, string password)
{
string uri = $"/identitytoolkit/v3/relyingparty/verifyPassword?key={_appKey}";
var response = await _httpClient.PostAsJsonAsync(uri, new FireBaseLoginInfo
{
email = username,
password = password,
});

var result = await response.Content.ReadAsAsync<GoogleToken>();

return new Token
{
token_type = "Bearer",
access_token = result.IdToken,
id_token = result.IdToken,
expires_in = int.Parse(result.ExpiresIn),
};
}
}
public class FirebaseAuthenticationClient : IFirebaseAuthenticationClient
{
private readonly string _appKey;
private readonly HttpClient _httpClient;

public FirebaseAuthenticationClient(IConfiguration configuration, HttpClient httpClient)
{
_appKey = configuration.GetValue<string>("FirebaseAppKey");
_httpClient = httpClient;
}
public async Task<Token> Login(string username, string password)
{
string uri = $"/identitytoolkit/v3/relyingparty/verifyPassword?key={_appKey}";
var response = await _httpClient.PostAsJsonAsync(uri, new FireBaseLoginInfo
{
email = username,
password = password,
});

var result = await response.Content.ReadAsAsync<GoogleToken>();

return new Token
{
token_type = "Bearer",
access_token = result.IdToken,
id_token = result.IdToken,
expires_in = int.Parse(result.ExpiresIn),
};
}
}
appsettings.Production.json:
...
"Auth": {
"Authority": "https://securetoken.google.com/*firebase project id here*",
"Issuer": "https://securetoken.google.com/*firebase project id here*",
"Audience": "*firebase project id here*"
},
...
...
"Auth": {
"Authority": "https://securetoken.google.com/*firebase project id here*",
"Issuer": "https://securetoken.google.com/*firebase project id here*",
"Audience": "*firebase project id here*"
},
...
Dependencies: - FirebaseAdmin (2.3.0) - Microsoft.AspNet.WebApi.Client (5.2.9) - Microsoft.AspNetCore.Authentication.JwtBearer (7.0.4) - Microsoft.AspNetCore.OpenApi (7.0.3) - Swashbuckle.AspNetCore (6.4.0)
Kouhai
Kouhai16mo ago
So Login endpoint returns a valid JWT but subsequent requests return 401? Are you sure JWT is getting sent with your subsequent requests?
Accord
Accord16mo ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
NDOT
NDOT16mo ago
hi, sorry for revinving this but i'm with the same problem (i didn't want to polute and create a new Post)
Kouhai
Kouhai16mo ago
What's the problem again 😅 ?
NDOT
NDOT16mo ago
fine basically i did an endpoint to create the JWT at the end it returns me a ok look like JWT but when i use it, it returns 401 Unauthourized and Bearer error="invalid_token", error_description="The signature key was not found"
Kouhai
Kouhai16mo ago
Okay, first what have you added a reference to Microsoft.AspNetCore.Authentication.JwtBearer
NDOT
NDOT16mo ago
yes
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using SistemaDeTarefas.Models;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using SistemaDeTarefas.Models;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
using Microsoft.AspNetCore.Authentication.JwtBearer;
mine ones
var key = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(_configuration.GetSection("Jwt:Key").Value));

var cred = new SigningCredentials(key, SecurityAlgorithms.HmacSha512Signature);

var token = new JwtSecurityToken
(
claims: claims,
expires: DateTime.Now.AddSeconds(1800), signingCredentials : cred
);
var jwt = new JwtSecurityTokenHandler().WriteToken(token);
return jwt;
var key = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(_configuration.GetSection("Jwt:Key").Value));

var cred = new SigningCredentials(key, SecurityAlgorithms.HmacSha512Signature);

var token = new JwtSecurityToken
(
claims: claims,
expires: DateTime.Now.AddSeconds(1800), signingCredentials : cred
);
var jwt = new JwtSecurityTokenHandler().WriteToken(token);
return jwt;
that's basically the function that creates my JWT's
Kouhai
Kouhai16mo ago
How did you add your config the auth services ?
NDOT
NDOT16mo ago
wdym? i mean, i did just make a simple, Login endpoint, that creates a JWT that allows you to access the other endpoints btw i'm using .NET 6 not fast api, just a common webapi
Kouhai
Kouhai16mo ago
Sorry, what I meant is how did add your auth servics, like .AddJwtBearer and .AddAuthentication
NDOT
NDOT16mo ago
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
Kouhai
Kouhai16mo ago
No like, show the AddJwtBearer and AddAuthentication calls
NDOT
NDOT16mo ago
my whole method that creates the JWT is that>
List<Claim> claims = new List<Claim>
{
new Claim(ClaimTypes.Name, user.Username)
};
var key = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes("absca4234srhaowurha3uo"));

var cred = new SigningCredentials(key, SecurityAlgorithms.HmacSha512Signature);

var token = new JwtSecurityToken
(
claims: claims,
expires: DateTime.Now.AddSeconds(1800),
signingCredentials : cred
);

var jwt = new JwtSecurityTokenHandler().WriteToken(token);
return jwt;
List<Claim> claims = new List<Claim>
{
new Claim(ClaimTypes.Name, user.Username)
};
var key = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes("absca4234srhaowurha3uo"));

var cred = new SigningCredentials(key, SecurityAlgorithms.HmacSha512Signature);

var token = new JwtSecurityToken
(
claims: claims,
expires: DateTime.Now.AddSeconds(1800),
signingCredentials : cred
);

var jwt = new JwtSecurityTokenHandler().WriteToken(token);
return jwt;
Kouhai
Kouhai16mo ago
You aren't calling AddJwtBearer at all?
NDOT
NDOT16mo ago
hmm... no ? i was just following a tutorial (and in the tutorial did work so i thought it would be something wrong in my code)
Kouhai
Kouhai16mo ago
It won't work without adding JWT auth services, so the tutorial should have that.
NDOT
NDOT16mo ago
where can i insert then?
Kouhai
Kouhai16mo ago
Do you have startup.cs file?
NDOT
NDOT16mo ago
nop .net 6 doesn't have one, it's the Program.cs, but works almost the same way i think
Kouhai
Kouhai16mo ago
Yeah, it's the same, you have to add couples of things 1 - The middleware for authentication and authorization 2 - Add authentication services by calling AddAuthentication and then adding AddJwtBearer
NDOT
NDOT16mo ago
builder.Services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = domain;
options.Audience =builder.Configuration["Auth0:Audience"];
// If the access token does not have a `sub` claim, `User.Identity.Name` will be `null`. Map it to a different claim by setting the NameClaimType below.
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = ClaimTypes.NameIdentifier
};
});
builder.Services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = domain;
options.Audience =builder.Configuration["Auth0:Audience"];
// If the access token does not have a `sub` claim, `User.Identity.Name` will be `null`. Map it to a different claim by setting the NameClaimType below.
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = ClaimTypes.NameIdentifier
};
});
i did put both, but i didn't find about how to add the middleware in .NET 6 without using the Startup.cs
Accord
Accord16mo ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
NDOT
NDOT16mo ago
update> i actually just get a read on a tutorial and find out how to make it work, and worked, thanks