I got an Angular application that let's users login with a Microsoft and Google Account. Once the login step is over, I got an Access Token which is sent to the API for validation to secure the application. The API is a ASP.net Core 6 application.
I successfully validate an Access Token emitted by Google with the code below. But, I need to do the same with an Access Token emitted by Microsoft.
builder.Services.AddAuthentication(x =>
{
x.DefaultSignInScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultSignOutScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.SecurityTokenValidators.Add(new MicrosoftTokenValidator()); // todo
options.SecurityTokenValidators.Add(new GoogleTokenValidator());
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(appSettings.AccessTokenSecretKey)),
ValidateIssuer = false,
ValidateAudience = false,
ValidIssuer = appSettings.AccessTokenValidIssuer,
ValidAudience = appSettings.AccessTokenValidAudience
};
});
With Google things are easy with GoogleJsonWebSignature.ValidateAsync from using Google.Apis.Auth;
public class GoogleTokenValidator : ISecurityTokenValidator
{
private readonly JwtSecurityTokenHandler _tokenHandler;
public GoogleTokenValidator()
{
_tokenHandler = new JwtSecurityTokenHandler();
}
public bool CanValidateToken => true;
public int MaximumTokenSizeInBytes { get; set; } = TokenValidationParameters.DefaultMaximumTokenSizeInBytes;
public bool CanReadToken(string securityToken)
{
return _tokenHandler.CanReadToken(securityToken);
}
public ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken)
{
validatedToken = null;
var payload = GoogleJsonWebSignature.ValidateAsync(securityToken, new GoogleJsonWebSignature.ValidationSettings()).Result; // here is where I delegate to Google to validate
var claims = new List<Claim>
{
new Claim(ClaimTypes.NameIdentifier, payload.Name),
new Claim(ClaimTypes.Name, payload.Name),
new Claim(JwtRegisteredClaimNames.FamilyName, payload.FamilyName),
new Claim(JwtRegisteredClaimNames.GivenName, payload.GivenName),
new Claim(JwtRegisteredClaimNames.Email, payload.Email),
new Claim(JwtRegisteredClaimNames.Sub, payload.Subject),
new Claim(JwtRegisteredClaimNames.Iss, payload.Issuer),
};
try
{
var principle = new ClaimsPrincipal();
principle.AddIdentity(new ClaimsIdentity(claims, "Password"));
return principle;
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
}
I try to find the same validation pattern for Microsoft Provider but without any success. This is why I'm asking the the SO community to get some answers or some help.
I found Microsoft Graph API and Azure Identity, but it leads me nowhere.
I found the answer to my question. Yesterday, I was thinking Microsoft could have done something like GoogleJsonWebSignature and I was trying to find it. It was a mistake!
I realized I can decode every access token with System.IdentityModel.Tokens.Jwt found at https://jwt.io/libraries.
I can then read the tokens this way inside public ClaimsPrincipal ValidateToken method and then write my validation logic :
var token = new JwtSecurityToken(securityToken);