Search code examples
oauth-2.0azure-active-directory

Unable to get OAuth2.0 get access token


I get the below error:

{"error":"invalid_grant","error_description":"AADSTS9002313: Invalid request. Request is malformed or invalid. Trace ID: 68670f14-0eff-403c-9681-f99d5d3d5700 Correlation ID: 0f112149-c7fb-410a-b08e-6db049f63751 Timestamp: 2024-05-28 07:20:28Z","error_codes":[9002313],"timestamp":"2024-05-28 07:20:28Z","trace_id":"68670f14-0eff-403c-9681-f99d5d3d5700","correlation_id":"0f112149-c7fb-410a-b08e-6db049f63751","error_uri":"https://login.microsoftonline.com/error?code=9002313"}

Here is my current code:**


`
TokenResponse token = null;
            string tokenEndPoint = "https://login.microsoftonline.com/9fa257f-...c3/oauth2/token";

            string clientId = Common.ConfigWrapper.Get("OAuthClientID", "");
            string clientSecret = Common.ConfigWrapper.Get("OAuthclientSecret", "");
            string redirectUri = Common.ConfigWrapper.Get("OAuthRedirectUri", "");

            string encodedRedirectUri = Uri.EscapeDataString(redirectUri);

            // Set the request valuers.
            var postData = new List<KeyValuePair<string, string>>
            {
                new KeyValuePair<string, string>("grant_type", "authorization_code"),
                new KeyValuePair<string, string>("code", code),
                new KeyValuePair<string, string>("client_id", clientId),
                new KeyValuePair<string, string>("client_secret", clientSecret),
                new KeyValuePair<string, string>("redirect_uri", redirectUri)
            };
            using (var httpClient = new HttpClient())
            {
                HttpContent content = new FormUrlEncodedContent(postData);

                using (var response = await httpClient.PostAsync(tokenEndPoint, content))
                {
                    string responseString = await response.Content.ReadAsStringAsync();

                    if (response.StatusCode == System.Net.HttpStatusCode.OK)
                    {
                        token = JsonConvert.DeserializeObject<TokenResponse>(responseString);
                    }
                    else
                    {
                        // Optionally log or handle the error response
                        var errorResponse = JsonConvert.DeserializeObject<Dictionary<string, object>>(responseString);
                        Console.WriteLine($"Error: {errorResponse["error"]}, Description: {errorResponse["error_description"]}");
                    }
                }
            }

            return token;
`

**Here is one of the 10 000 other wys of trying to get some type of positive result back:

In postman, I got it to work using the below, I think postman probably adds other headers which makes the post successfull, but I can't which if there are any. Any advise or help to what I am doing wrong/missing, I have been struggling for two days now. **

`
string tokenEndPoint = "https://login.microsoftonline.com/9fa27...4c3/oauth2/token";
string clientId = Common.ConfigWrapper.Get("OAuthClientID", "");
string clientSecret = Common.ConfigWrapper.Get("OAuthclientSecret", "");
string redirectUri = Common.ConfigWrapper.Get("OAuthRedirectUri", "");

string encodedRedirectUri = Uri.EscapeDataString(redirectUri);

using (var client = new HttpClient())
   {
        // Add headers explicitly
        client.DefaultRequestHeaders.Add("Pragma", "no-cache");
        client.DefaultRequestHeaders.Add("Cache-Control", "no-store, no-cache");

        var requestBody = new StringContent("{ \"key\": \"value\" }", Encoding.UTF8"application/json");

        var postData = new List<KeyValuePair<string, string>>
        {
           new KeyValuePair<string, string>("grant_type", "authorization_code"),
           new KeyValuePair<string, string>("code", $"{code}"),
           new KeyValuePair<string, string>("redirect_uri", $"{encodedRedirectUri}"),
           new KeyValuePair<string, string>("client_id", $"{clientId}"),
           new KeyValuePair<string, string>("client_secret", $"{clientSecret}")
        };

        var content = new FormUrlEncodedContent(postData);

        var response = client.PostAsync(tokenEndPoint,
              new FormUrlEncodedContent(new Dictionary<string, string>() 
               {
                   { "client_id", clientId},
                   { "scope", "123"},
                   { "redirect_uri", encodedRedirectUri },
                   { "refresh_token", code},
                   { "grant_type", "refresh_token" },
                   { "client_secret", clientSecret }
                })).Result;

         var responseContent = response.Content.ReadAsStringAsync().Result;

         if (!response.IsSuccessStatusCode)
         {
              responseContent = await response.Content.ReadAsStringAsync();

              Console.WriteLine($"Error: {response.StatusCode}");
              Console.WriteLine($"Response: {responseContent}");

              Logr.LogINF("MFA Login failed :" + responseContent);
              var error = $"Token request failed. Status Code: {response.StatusCode}.";

              return error;
          }

         response.EnsureSuccessStatusCode();

         var responseString = await response.Content.ReadAsStringAsync();

         var tokenReponse = JsonConvert.DeserializeObject<TokenResponse>(responseString);

         return tokenReponse;
   }``

Solution

  • To generate the auth-code, use the below endpoint:

    https://login.microsoftonline.com/TenantID/oauth2/authorize?
    &client_id=ClientID
    &response_type=code
    &redirect_uri=RedirectURL
    &response_mode=query
    &scope=offline_access User.Read 
    &state=12345
    

    enter image description here

    Modify the code to generate access and refresh tokens and to refresh the access token:

    namespace OAuthExample
    {
        public class TokenResponse
        {
            [JsonProperty("access_token")]
            public string AccessToken { get; set; }
    
            [JsonProperty("token_type")]
            public string TokenType { get; set; }
    
            [JsonProperty("expires_in")]
            public int ExpiresIn { get; set; }
    
            [JsonProperty("refresh_token")]
            public string RefreshToken { get; set; }
        }
    
        public class OAuthClient
        {
            private string clientId = "ClientID";
            private string clientSecret = "ClientSecret";
            private string redirectUri = "https://jwt.ms";
            private string tokenEndPoint = "https://login.microsoftonline.com/TenantID/oauth2/token";
    
            public async Task<TokenResponse> GetTokenAsync(string code)
            {
                TokenResponse token = null;
    
                var postData = new List<KeyValuePair<string, string>>
                {
                    new KeyValuePair<string, string>("grant_type", "authorization_code"),
                    new KeyValuePair<string, string>("code", code),
                    new KeyValuePair<string, string>("client_id", clientId),
                    new KeyValuePair<string, string>("client_secret", clientSecret),
                    new KeyValuePair<string, string>("redirect_uri", redirectUri)
                };
    
                using (var httpClient = new HttpClient())
                {
                    HttpContent content = new FormUrlEncodedContent(postData);
    
                    using (var response = await httpClient.PostAsync(tokenEndPoint, content))
                    {
                        string responseString = await response.Content.ReadAsStringAsync();
    
                        if (response.StatusCode == System.Net.HttpStatusCode.OK)
                        {
                            token = JsonConvert.DeserializeObject<TokenResponse>(responseString);
                        }
                        else
                        {
                            var errorResponse = JsonConvert.DeserializeObject<Dictionary<string, object>>(responseString);
                            Console.WriteLine($"Error: {errorResponse["error"]}, Description: {errorResponse["error_description"]}");
                        }
                    }
                }
    
                return token;
            }
    
            public async Task<TokenResponse> RefreshTokenAsync(string refreshToken)
            {
                TokenResponse token = null;
    
                var postData = new Dictionary<string, string>
                {
                    { "client_id", clientId },
                    { "scope", "https://graph.microsoft.com/.default" },
                    { "redirect_uri", redirectUri },
                    { "refresh_token", refreshToken },
                    { "grant_type", "refresh_token" },
                    { "client_secret", clientSecret }
                };
    
                using (var httpClient = new HttpClient())
                {
                    HttpContent content = new FormUrlEncodedContent(postData);
    
                    using (var response = await httpClient.PostAsync(tokenEndPoint, content))
                    {
                        string responseString = await response.Content.ReadAsStringAsync();
    
                        if (!response.IsSuccessStatusCode)
                        {
                            Console.WriteLine($"Error: {response.StatusCode}");
                            Console.WriteLine($"Response: {responseString}");
                        }
                        else
                        {
                            token = JsonConvert.DeserializeObject<TokenResponse>(responseString);
                        }
                    }
                }
    
                return token;
            }
        }
    
        class Program
        {
            static async Task Main(string[] args)
            {
                string authorizationCode = "auth-code-here"; 
    
                var oauthClient = new OAuthClient();
                TokenResponse token = await oauthClient.GetTokenAsync(authorizationCode);
    
                if (token != null)
                {
                    Console.WriteLine($"Access Token: {token.AccessToken}");
                    Console.WriteLine($"Token Type: {token.TokenType}");
                    Console.WriteLine($"Expires In: {token.ExpiresIn}");
                    Console.WriteLine($"Refresh Token: {token.RefreshToken}");
    
                    TokenResponse refreshedToken = await oauthClient.RefreshTokenAsync(token.RefreshToken);
    
                    if (refreshedToken != null)
                    {
                        Console.WriteLine("Refreshed Token:");
                        Console.WriteLine($"Access Token: {refreshedToken.AccessToken}");
                        Console.WriteLine($"Token Type: {refreshedToken.TokenType}");
                        Console.WriteLine($"Expires In: {refreshedToken.ExpiresIn}");
                        Console.WriteLine($"Refresh Token: {refreshedToken.RefreshToken}");
                    }
                    else
                    {
                        Console.WriteLine("Failed to refresh token.");
                    }
                }
                else
                {
                    Console.WriteLine("Failed to obtain token.");
                }
            }
        }
    }
    
    

    enter image description here

    The access and refresh token and refreshed access and refresh token got generated successfully:

    enter image description here