'Xamarin login authentication using JWT

I'm developing my first Xamarin cross-platform application for Android and iOS (using Xamarin Forms). The application will require the user to login using a REST API and stay authenticated.

I want to use the token from my API, which is JWT, on my Xamarin application for the user to login

I don't know how to do this and all I have seen is with OAuth authentication.

Here is how I generate the token on my API project

private string GenerateToken(CrUserInfo user)
        {
            //Header
            var symmetricSecurityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Authentication:SecretKey"]));
            var signingCredentials = new SigningCredentials(symmetricSecurityKey, SecurityAlgorithms.HmacSha256);
            var header = new JwtHeader(signingCredentials);

            //Claims
            var claims = new[]
            {
                new Claim(ClaimTypes.Name, user.Username),
                new Claim("User", user.Displayname),
                new Claim(ClaimTypes.Role, user.Role.ToString()),
            };

            //Payload
            var payload = new JwtPayload
            (
                _configuration["Authentication:Issuer"],
                _configuration["Authentication:Audience"],
                claims,
                DateTime.Now,
                DateTime.Now.AddMinutes(300)
            );

            var token = new JwtSecurityToken(header, payload);

            return new JwtSecurityTokenHandler().WriteToken(token);
}

Here is my post method which returns the Token

[HttpPost]
        [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(string))]
        [ProducesResponseType((int)HttpStatusCode.BadRequest)]
        [ProducesResponseType((int)HttpStatusCode.Unauthorized)]
        public async Task<IActionResult> Authentication(UserLogin login)
        {
            //if it is a valid user 
            var validation = await IsValidUser(login);
            if (validation.Item1)
            {
                if(validation.Item2 != null)
                {
                    var token = GenerateToken(validation.Item2);
                    return Ok(new { token });
                }
            }

            return NotFound("Unvalid User");
        }

And I'm now trying to login a user on my Xamarin project but, as I said, all I see is OAuth authentication. The closest question I've seen was this one Xamarin.Forms how to access the current logged in user's Id and other information? - Stack Overflow but I don't know how to implement it.



Solution 1:[1]

First of all I used a different Library to Create the Jwt-Token. The implementation seems correct. In my Example e return a DTO from a Shared Project, because i also want to transmit the UserId and the exipredate But for example here is my code:

        var claims = new List<Claim>
        {
            new(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
            new(ClaimTypes.NameIdentifier, user.Id),
        };
        var userRoles = await _userManager.GetRolesAsync(user);
        claims.AddRange(userRoles.Select(x => new Claim(ClaimTypes.Role, x)));

        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JWT:Secret"]));
        var jwtSecurityToken = new JwtSecurityToken(
            _configuration["JWT:ValidIssuer"],
            claims: claims,
            expires: DateTime.Now.AddDays(1),
            signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256)
        );

        return new AuthDto
        {
            Id = user.Id,
            Token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken),
            ExpiryDate = jwtSecurityToken.ValidTo
        };

In the shared App Project we used the ViewModel approach. There I store the token in the local app database. To check if the token is present I created a baseViewmodel which checks if the logintoken is active on each request.

To validate the token in the app I have implemented following class:

public class ValidatorImpl<T> : IValidator<T> where T : class
{
    public bool IsValid(T validateObject) => !ValidateObject(validateObject).Any();

    public IReadOnlyList<string> ValidateObject(T validateObject)
    {
        var context = new ValidationContext(validateObject);
        var results = new List<ValidationResult>();
        Validator.TryValidateObject(validateObject, context, results, true);
        return results.Select(vr => vr.Errormessage).ToList();
    }
}

before I save the token to the database i validate it like that:

if (!new ValidatorImpl<LoginToken>().IsValid(loginToken))
            return false;

To deserialize the token do this:

private static JwtSecurityToken GetJwtSecurityToken(string token) => new JwtSecurityToken(token);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1