How do I get an OAuth 2.0 authentication token in C#

后端 未结 7 1213
借酒劲吻你
借酒劲吻你 2020-12-02 11:15

I have these settings:

  • Auth URL (which happens to be a \"https://login.microsoftonline.com/...\") if that helps.
  • Access Token URL \"https://service.en
7条回答
  •  臣服心动
    2020-12-02 11:35

    The Rest Client answer is perfect! (I upvoted it)

    But, just in case you want to go "raw"

    ..........

    I got this to work with HttpClient.

    /*
    .nuget\packages\newtonsoft.json\12.0.1
    .nuget\packages\system.net.http\4.3.4
    */
    
    using Newtonsoft.Json;
    using System;
    using System.Collections.Generic;
    using System.Net.Http;
    using System.Net.Http.Headers;
    using System.Threading.Tasks;
    using System.Web;
    
    
        private static async Task GetElibilityToken(HttpClient client)
        {
            string baseAddress = @"https://blah.blah.blah.com/oauth2/token";
    
            string grant_type = "client_credentials";
            string client_id = "myId";
            string client_secret = "shhhhhhhhhhhhhhItsSecret";
    
            var form = new Dictionary
                    {
                        {"grant_type", grant_type},
                        {"client_id", client_id},
                        {"client_secret", client_secret},
                    };
    
            HttpResponseMessage tokenResponse = await client.PostAsync(baseAddress, new FormUrlEncodedContent(form));
            var jsonContent = await tokenResponse.Content.ReadAsStringAsync();
            Token tok = JsonConvert.DeserializeObject(jsonContent);
            return tok;
        }
    
    
    internal class Token
    {
        [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; }
    }       
    

    Here is another working example (based off the answer above)......with a few more tweaks. Sometimes the token-service is finicky:

        private static async Task GetATokenToTestMyRestApiUsingHttpClient(HttpClient client)
        {
            /* this code has lots of commented out stuff with different permutations of tweaking the request  */
    
            /* this is a version of asking for token using HttpClient.  aka, an alternate to using default libraries instead of RestClient */
    
            OAuthValues oav = GetOAuthValues(); /* object has has simple string properties for TokenUrl, GrantType, ClientId and ClientSecret */
    
            var form = new Dictionary
                    {
                        { "grant_type", oav.GrantType },
                        { "client_id", oav.ClientId },
                        { "client_secret", oav.ClientSecret }
                    };
    
            /* now tweak the http client */
            client.DefaultRequestHeaders.Clear();
            client.DefaultRequestHeaders.Add("cache-control", "no-cache");
    
            /* try 1 */
            ////client.DefaultRequestHeaders.Add("content-type", "application/x-www-form-urlencoded");
    
            /* try 2 */
            ////client.DefaultRequestHeaders            .Accept            .Add(new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));//ACCEPT header
    
            /* try 3 */
            ////does not compile */client.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
    
            ////application/x-www-form-urlencoded
    
            HttpRequestMessage req = new HttpRequestMessage(HttpMethod.Post, oav.TokenUrl);
            /////req.RequestUri = new Uri(baseAddress);
    
            req.Content = new FormUrlEncodedContent(form);
    
            ////string jsonPayload = "{\"grant_type\":\"" + oav.GrantType + "\",\"client_id\":\"" + oav.ClientId + "\",\"client_secret\":\"" + oav.ClientSecret + "\"}";
            ////req.Content = new StringContent(jsonPayload,                                                Encoding.UTF8,                                                "application/json");//CONTENT-TYPE header
    
            req.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
    
            /* now make the request */
            ////HttpResponseMessage tokenResponse = await client.PostAsync(baseAddress, new FormUrlEncodedContent(form));
            HttpResponseMessage tokenResponse = await client.SendAsync(req);
            Console.WriteLine(string.Format("HttpResponseMessage.ReasonPhrase='{0}'", tokenResponse.ReasonPhrase));
    
            if (!tokenResponse.IsSuccessStatusCode)
            {
                throw new HttpRequestException("Call to get Token with HttpClient failed.");
            }
    
            var jsonContent = await tokenResponse.Content.ReadAsStringAsync();
            Token tok = JsonConvert.DeserializeObject(jsonContent);
    
            return tok;
        }
    

    APPEND

    Bonus Material!

    If you ever get a

    "The remote certificate is invalid according to the validation procedure."

    exception......you can wire in a handler to see what is going on (and massage if necessary)

    using System;
    using System.Collections.Generic;
    using System.Text;
    using Newtonsoft.Json;
    using System.Net.Http;
    using System.Net.Http.Headers;
    using System.Threading.Tasks;
    using System.Web;
    using System.Net;
    
    namespace MyNamespace
    {
        public class MyTokenRetrieverWithExtraStuff
        {
            public static async Task GetElibilityToken()
            {
                using (HttpClientHandler httpClientHandler = new HttpClientHandler())
                {
                    httpClientHandler.ServerCertificateCustomValidationCallback = CertificateValidationCallBack;
                    using (HttpClient client = new HttpClient(httpClientHandler))
                    {
                        return await GetElibilityToken(client);
                    }
                }
            }
    
            private static async Task GetElibilityToken(HttpClient client)
            {
                // throws certificate error if your cert is wired to localhost // 
                //string baseAddress = @"https://127.0.0.1/someapp/oauth2/token";
    
                //string baseAddress = @"https://localhost/someapp/oauth2/token";
    
            string baseAddress = @"https://blah.blah.blah.com/oauth2/token";
    
            string grant_type = "client_credentials";
            string client_id = "myId";
            string client_secret = "shhhhhhhhhhhhhhItsSecret";
    
            var form = new Dictionary
                    {
                        {"grant_type", grant_type},
                        {"client_id", client_id},
                        {"client_secret", client_secret},
                    };
    
                HttpResponseMessage tokenResponse = await client.PostAsync(baseAddress, new FormUrlEncodedContent(form));
                var jsonContent = await tokenResponse.Content.ReadAsStringAsync();
                Token tok = JsonConvert.DeserializeObject(jsonContent);
                return tok;
            }
    
            private static bool CertificateValidationCallBack(
            object sender,
            System.Security.Cryptography.X509Certificates.X509Certificate certificate,
            System.Security.Cryptography.X509Certificates.X509Chain chain,
            System.Net.Security.SslPolicyErrors sslPolicyErrors)
            {
                // If the certificate is a valid, signed certificate, return true.
                if (sslPolicyErrors == System.Net.Security.SslPolicyErrors.None)
                {
                    return true;
                }
    
                // If there are errors in the certificate chain, look at each error to determine the cause.
                if ((sslPolicyErrors & System.Net.Security.SslPolicyErrors.RemoteCertificateChainErrors) != 0)
                {
                    if (chain != null && chain.ChainStatus != null)
                    {
                        foreach (System.Security.Cryptography.X509Certificates.X509ChainStatus status in chain.ChainStatus)
                        {
                            if ((certificate.Subject == certificate.Issuer) &&
                               (status.Status == System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.UntrustedRoot))
                            {
                                // Self-signed certificates with an untrusted root are valid. 
                                continue;
                            }
                            else
                            {
                                if (status.Status != System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.NoError)
                                {
                                    // If there are any other errors in the certificate chain, the certificate is invalid,
                                    // so the method returns false.
                                    return false;
                                }
                            }
                        }
                    }
    
                    // When processing reaches this line, the only errors in the certificate chain are 
                    // untrusted root errors for self-signed certificates. These certificates are valid
                    // for default Exchange server installations, so return true.
                    return true;
                }
    
    
                /* overcome localhost and 127.0.0.1 issue */
                if ((sslPolicyErrors & System.Net.Security.SslPolicyErrors.RemoteCertificateNameMismatch) != 0)
                {
                    if (certificate.Subject.Contains("localhost"))
                    {
                        HttpRequestMessage castSender = sender as HttpRequestMessage;
                        if (null != castSender)
                        {
                            if (castSender.RequestUri.Host.Contains("127.0.0.1"))
                            {
                                return true;
                            }
                        }
                    }
                }
    
                return false;
    
            }
    
    
            public class Token
            {
                [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; }
            }
    
        }
    }
    

    ........................

    I recently found (Jan/2020) an article about all this. I'll add a link here....sometimes having 2 different people show/explain it helps someone trying to learn it.

    http://luisquintanilla.me/2017/12/25/client-credentials-authentication-csharp/

提交回复
热议问题