Search code examples
c#discord.net

DiscordAuthentication AccessToken is returns null


I am trying to use Discord Authentication to sign to my app and I want to get the user information.

This my login method:

public static void Login(string clientId, string redirectUri)
        {
            var url = $"https://discord.com/api/oauth2/authorize?client_id={clientId}&redirect_uri={redirectUri}&response_type=code&scope=identify";
            Console.WriteLine($"Redirecting to: {url}");
            var ps = new ProcessStartInfo(url)
            {
                UseShellExecute = true,
                Verb = "open"
            };
            Process.Start(ps);
        }

And this is where I get the accesstoken and user information:

        public static async Task<string> GetAccessTokenAsync(string clientId, string clientSecret, string code, string redirectUri)
        {
            var content = new FormUrlEncodedContent(new[]
            {
                new KeyValuePair<string, string>("client_id", clientId),
                new KeyValuePair<string, string>("client_secret", clientSecret),
                new KeyValuePair<string, string>("grant_type", "authorization_code"),
                new KeyValuePair<string, string>("code", code),
                new KeyValuePair<string, string>("redirect_uri", redirectUri),
                new KeyValuePair<string, string>("scope", "identify"),
            });

            var response = await _client.PostAsync("https://discord.com/api/oauth2/token", content);
            response.EnsureSuccessStatusCode();

            var json = await response.Content.ReadAsStringAsync();
            var accessTokenResponse = JsonSerializer.Deserialize<AccessTokenResponse>(json);
            return accessTokenResponse.AccessToken;
        }

        public static async Task<(string, string)> GetUserInfoAsync(string accessToken)
        {
            _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

            var response = await _client.GetAsync("https://discord.com/api/users/@me");
            response.EnsureSuccessStatusCode();

            var json = await response.Content.ReadAsStringAsync();
            var user = JsonSerializer.Deserialize<User>(json);

            return (user.Id, user.Username);
        }

This is my json variable:

{
"access_token": "CF2CiBR4wb7VIY8VyDZbhOFeCdYFUw",
"expires_in": 604800, 
"refresh_token": "PDV79lSv765ISV77HIAJL8mtJt2JeY", 
"scope": "identify", 
"token_type": "Bearer"
}

And this is my AccessTokenResponse model:

    public class AccessTokenResponse
    {
        public string AccessToken { get; set; }
        public int ExpiresIn { get; set; }
        public string RefreshToken { get; set; }
        public string Scope { get; set; }
        public string TokenType { get; set; }
    }

But the accesstoken is returning null. The response status is 200 ok. Where did I do wrong?


Solution

  • Your C# model doesn't match the incoming JSON. Use the JsonPropertyName attribute to map your properties to their JSON keys.

    Note: For those using Newtonsoft.Json, it's the JsonProperty attribute.


    Specifically, take note of access_token, expires_in, refresh_token, and token_type and how each has an underscore (_) in its name in the JSON but not your C# model:

    public string AccessToken { get; set; }
    public int ExpiresIn { get; set; }
    public string RefreshToken { get; set; }
    public string TokenType { get; set; }
    

    Adding the JsonPropertyName attribute to your property resolves the issue while respecting C# naming conventions:

    public class AccessTokenResponse
    {
        [JsonPropertyName("access_token")] public string AccessToken { get; set; }
        [JsonPropertyName("expires_in")] public int ExpiresIn { get; set; }
        [JsonPropertyName("refresh_token")] public string RefreshToken { get; set; }
        [JsonPropertyName("scope")] public string Scope { get; set; }
        [JsonPropertyName("token_type")] public string TokenType { get; set; }
    }
    

    Try it on Dot NET Fiddle!