IncrediblePony
IncrediblePony

Reputation: 752

.net mvc JWT token changes utf-8 chars

I have a JWT token that I use for authentication. In my Database I have a customerUser that cointains a firstName: Tim and a lastName: Børge but after my code reads from my Database and creates a JWT the structure in the token makes it so that

"firstName":"Tim"
"lastName":"Børge"

And this is what I store in my localstorage. And that is a problem for when I print out the users name on my webpage. I have checked my source code and it all seems to boil down to this line:

        try
        {
            var user = Membership.GetUser(username, true);
            var jwt = GetJwtFromMembershipAccountId((int)(user?.ProviderUserKey??0));
            return this.Request.CreateResponse(
                HttpStatusCode.OK, 
                jwt, 
                new TextMediaTypeFormatter()
            );
        }
        catch
        {
            return Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "Error logging in!");
        }

Up until that point my data contains my UTF-8 chars. Any ideas?

EDIT the JWT:

eyJpc3MiOiJLb2xsZWN0by5pbyA0LjAiLCJpYXQiOjE1NzQzMzA3MTguMCwiZXhwIjoxNTc1NTQwMzE4LjAsInN1YmplY3QiOiJtYW5kQG5pcmFzLmRrIiwiYXVkIjoiS29sbGVjdG8uaW8gNC4wIiwidHlwIjoiSldUIiwiYWxnIjoiSFMyNTYifQ.eyJjdXN0b21lcl9pZCI6IjU5YTkyYWFmYWU3YTcxMWIzODkwMTc2MSIsImFwaV9rZXkiOiI1Y2M4MTE2MDdmYTlkNjg3ZDI2NTkyZmUiLCJjdXN0b21lclVzZXJfaWQiOiI1ZDljM2FmNGY3MThiNDRlOTBiYmJkMzMiLCJhY2NvdW50X2lkIjoxMDQ0LCJlbWFpbCI6Im1hbmRAbmlyYXMuZGsiLCJyb2xlcyI6WyJNb2JpbGVVc2VyIiwiTmlyYXNBZG1pbiIsIkFkbWluIl0sImdpdmVuX25hbWUiOiJNYWRzIiwiZmFtaWx5X25hbWUiOiJCw7h0a2VyIEFuZGVyc2VuIn0.OMx8VZesjvd92ZrfoSpAdICvl9bGP2UTQrFjYWDWpKY

My function:

private string GetJwtFromMembershipAccountId(int accountId)
        {
            var account = DBHelper.membershipAccountCollection.FindOneById(accountId);
            var customerUser = DBHelper.customerUserCollection.AsQueryable().FirstOrDefault(x => x.UserId == accountId);
            var customer = DBHelper.customerCollection.AsQueryable().FirstOrDefault(x => x.CustomerId == customerUser.CustomerId);


            var timeSinceEpoch = (DateTime.UtcNow - JwtValidator.UnixEpoch);
            var expirationTime = timeSinceEpoch.Add(new TimeSpan(14, 0, 0, 0)); /* 14 days from now */
            var kollectoAppHeader = WebConfigurationManager.AppSettings["App.Name"] + " " + WebConfigurationManager.AppSettings["App.Version"];
            //var kollectoAppHeader = "SmartInspect";

            var headers = new Dictionary<string, object>
            {
                { "iss", kollectoAppHeader },
                { "iat", Math.Round(timeSinceEpoch.TotalSeconds) },
                { "exp", Math.Round(expirationTime.TotalSeconds) },
                { "subject", account.Username },
                { "aud", kollectoAppHeader }
            };
            var payload = new Dictionary<string, object>
            {
                { "customer_id", customer.CustomerId.ToString() },
                { "api_key",  customer.ApiKey.ToString() },
                { "customerUser_id", customerUser.CustomerUserId.ToString() },
                { "account_id", account.AccountId },
                { "email", customerUser.Email },
                { "roles", account.Roles },
                { "given_name", customerUser?.FirstName ?? string.Empty },
                { "family_name", customerUser?.LastName ?? string.Empty }
            };
            var algorithm = new HMACSHA256Algorithm();
            var serializer = new JsonNetSerializer();
            var urlEncoder = new JwtBase64UrlEncoder();
            var encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
            return encoder.Encode(headers, payload, _ssoJwtPsk);
        }

Upvotes: 3

Views: 2643

Answers (1)

jps
jps

Reputation: 22505

There's nothing wrong with the encoding in the token!

Your JWT encode method correctly encodes your UTF-8 characters in base64url encoding and jwt.io correctly displays the decoded UTF-8 characters.

Your client and jstoolset.com/jwt are interpreting the decoded characters as ISO-8859-1 or Windows-1252 charset.

It can easily be proved that the encoding is correct.

For illustration purposes, I made a simpler token which contains the danish UTF-8 character ø as payload:

eyJhbGciOiJIUzI1NiJ9.eyLDuCI6IjEifQ.RR8UPmBsMqH-huDVtfRWK4FSrmBuNEDtoMPxE7hJWt8

the payload is:

{"ø":"1"}

If you take the payload eyLDuCI6IjEifQ you first have to transform it back to binary. The base64 character estands for the 6 bits 011110, y for 110010 and so on (check Wikipedia base64 for the full encoding table). Now we have to transform it back to 8 bits, so take the first 6 bits plus the first 2 bits of the next character, that will give you 01111011 or hexadecimal 7B, the ASCII value of { followed by 00100010 (hex 22, ASCII ") and so on.

The full conversion of the first characters results in the following hex codes:

7B 22 C3 B8 22

On UTF-8 encoder/decoder you can see that ø has the UTF-8 code C3 B8, all others codes can easily be found on any common ASCII-table:

{ " ø "

So you see, the token contains a correctly encoded UTF-8 character. It's up to your client to interpret the result as UTF-8 and not any other character set.

Upvotes: 3

Related Questions