0

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.

jps
  • 20,041
  • 15
  • 75
  • 79
mml
  • 111
  • 1
  • 10

1 Answers1

0

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);
Lars
  • 97
  • 7
  • Thank you, I don't know if I'm understanding all. What I want to know is how to get that token for a user to login on my Xamarin project, I guess that's your code which generates the token – mml Apr 26 '22 at 10:58
  • Yes this is the code to create the token in the web API. So in die App i have an LoginView, where the user inserts its data (username, password). With a httpclient I transfer the data to the API. [link](https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclient?view=net-6.0). Does this helps? – Lars Apr 26 '22 at 11:00
  • What I was asking is how to validate that token (from API) on a Xamarin project – mml Apr 26 '22 at 11:04
  • Oh my bad, then I understood the question wrong. I updated my post – Lars Apr 26 '22 at 11:13
  • Sorry I probably wrote the question poorly. Thank you! And how did you deserialized the token? – mml Apr 26 '22 at 11:16
  • Is that a safe method to use? Saving the token? – mml Apr 26 '22 at 11:25
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/244223/discussion-between-lars-and-mml). – Lars Apr 26 '22 at 11:47
  • did it work for you? – Lars Apr 27 '22 at 08:36
  • No... Thank's for your interest really. I'm still trying to get the token. I already have the code and I think it's ok but it will return 404 not found error. I'll post another question explaining this – mml Apr 27 '22 at 08:49