Home > Net >  How manually validate a JWT Access Token emitted by Microsoft Login Provider?
How manually validate a JWT Access Token emitted by Microsoft Login Provider?

Time:07-27

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.

CodePudding user response:

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);
  • Related