Skip to content
Advertisement

Error in decoding photo URL from Facebook login that stored in JWT Token

I’m using ASP.Net Core Identity to store user info in JWT Token. I found that there is a problem with decoding the token that consists of Url Photo from Facebook.

Here is the way I’m decoding the token with javascript:

JSON.parse(atob(token.split('.')[1]));

and it results in the following error:

Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.

Referring to this post I think that there must be some replacement in the back-end with C# on the photo URL. I applied the changes but it wasn’t useful.

Here is the URL I got from Facebook:

https://scontent-ams4-1.xx.fbcdn.net/v/t1.30497-1/84628273_176159830277856_972693363922829312_n.jpg?stp=c15.0.50.50a_cp0_dst-jpg_p50x50&_nc_cat=1&ccb=1-7&_nc_sid=12b3be&_nc_ohc=D3l7nXsZ3NgAX_SAb-s&_nc_ht=scontent-ams4-1.xx&edm=AP4hL3IEAAAA&oh=00_AT8ViyxqwFycpp5TQRkSMoM34pivsmHOhPZSVJfrdYMRdw&oe=62C47219

JSFiddle Example

UPDATE:

Create a token that include photo Url received from Facebook.

    public async Task<DtoAuthenticationResult> CreateTokenAsync(AppUser user)
    {
        var claims = new List<Claim>
        {
            new ("UserName", user.UserName),
            new ("PhotoUrl", user.ProfilePhotoUrl),
            new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
        };

        var roles = await _userManager.GetRolesAsync(user);

        claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));

        var cred = new SigningCredentials(_key, SecurityAlgorithms.HmacSha512);

        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(claims),
            //Expires = DateTime.Now.Add(_jwtSettings.TokenLifeTime),
            Expires = DateTime.UtcNow.AddSeconds(120),
            SigningCredentials = cred
        };

        var tokenHandler = new JwtSecurityTokenHandler();

        var token = tokenHandler.CreateToken(tokenDescriptor);
        
        return new DtoAuthenticationResult
        {
            Success = true,
            Token = tokenHandler.WriteToken(token)
        };

    }

client-side:

export class UserToken {
  token: string;
  success: string;
  errors: string[];
}


facebookAuth(model: SocialUser) {
   return this.http.post(this.baseUrl + 'account/facebookAuth', model)
   .pipe(map((response: UserToken) => {
       const user = response;
       this.setCurrentUser(response);
   }));
}


setCurrentUser(authResult: UserToken) {
    const user: User = this.getDecodedToken(authResult.token);
    ...
}


 getDecodedToken(token: string) : User {
    let u = JSON.parse(atob(token.split('.')[1]));
    let usr = new User();
    ...
 }

Update 2:

Token value :

eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJFbWFpbCI6Ik5pY2suZnVyeWZjYkBnbWFpbC5jb20iLCJJZCI6IjIwMCIsIlVzZXJOYW1lIjoiTmljayIsIlNleCI6IjAiLCJHZW5kZXIiOiIwIiwiUGhvdG9VcmwiOiJodHRwczovL3Njb250ZW50LWFtczQtMS54eC5mYmNkbi5uZXQvdi90MS4zMDQ5Ny0xLzg0NjI4MjczXzE3NjE1OTgzMDI3Nzg1Nl85NzI2OTMzNjM5MjI4MjkzMTJfbi5qcGc_c3RwPWMxNS4wLjUwLjUwYV9jcDBfZHN0LWpwZ19wNTB4NTAmX25jX2NhdD0xJmNjYj0xLTcmX25jX3NpZD0xMmIzYmUmX25jX29oYz1EM2w3blhzWjNOZ0FYX1NBYi1zJl9uY19odD1zY29udGVudC1hbXM0LTEueHgmZWRtPUFQNGhMM0lFQUFBQSZvaD0wMF9BVDhWaXl4cXdGeWNwcDVUUVJrU01vTTM0cGl2c21IT2hQWlNWSmZyZFlNUmR3Jm9lPTYyQzQ3MjE5IiwianRpIjoiZTFkMGZkZjktMjg2MS00NzUxLWJlY2ItYzM1MjRhZDY0YWEzIiwibmJmIjoxNjU0Njk2MDA0LCJleHAiOjE2NTQ2OTYxMjQsImlhdCI6MTY1NDY5NjAwNH0.MZRvz57yjCmtkZyCDfGu3RX2LZ3KglnMM3ZzTFE73Ln7TrPyQ5_EgeWr2w0fBLOIObN6KSs9Bwvcoya7gSf7Kg

Answer

You need to convert base64url encoding to the usual base64 first. Please Try this code:

var base64Url = token.split('.')[1];
    var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
    var jsonPayload = decodeURIComponent(atob(base64).split('').map(function(c) {
        return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
    }).join(''));

console.log(JSON.parse(jsonPayload));

https://jsfiddle.net/ukmr6vjd/

Advertisement