Paypal REST api call works from cURL, but not from C # code

I am trying to call Paypal api from my code. I created an account for the sandbox, and it works when I use curl, but my code does not work that way, returning 401 Unauthorized.

Here the curl command is as documented in Paypal

curl https://api.sandbox.paypal.com/v1/oauth2/token -H "Accept: application/json" -H "Accept-Language: en_US" -u "A****:E****" -d "grant_type=client_credentials" 

UPDATE: .Credentials doesn't .Credentials do the trick, it sets the Authorization header manually instead (see code)

Here's the code (inherently clipped):

  HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("https://api.sandbox.paypal.com/v1/oauth2/token"); request.Method = "POST"; request.Accept = "application/json"; request.Headers.Add("Accept-Language:en_US") // this doesn't work: **request.Credentials = new NetworkCredential("A****", "E****");** // DO THIS INSTEAD **string authInfo = Convert.ToBase64String(System.Text.Encoding.Default.GetBytes("A****:E****"));** **request.Headers["Authorization"] = "Basic " + authInfo;** using (StreamWriter swt = new StreamWriter(request.GetRequestStream())) { swt.Write("grant_type=client_credentials"); } request.BeginGetResponse((r) => { try { HttpWebResponse response = request.EndGetResponse(r) as HttpWebResponse; // Exception here .... } catch (Exception x) { .... } // log the exception - 401 Unauthorized }, null); 

This is a request from the code captured by Fiddler (raw), for some reason there are no authorization parameters:

 POST https://api.sandbox.paypal.com/v1/oauth2/token HTTP/1.1 Accept: application/json Accept-Language: en_US Host: api.sandbox.paypal.com Content-Length: 29 Expect: 100-continue Connection: Keep-Alive grant_type=client_credentials 
+6
source share
4 answers

This works using HttpClient ... "RequestT" is common to PayPal request arguments, however it is not used. "ResponseT" is used, and this is a response from PayPal according to their documentation.

The 'PayPalConfig class' reads the clientid and secret from the web.config file using the ConfigurationManager. It should be remembered that the authorization header must be set to "Basic" NOT "Bearer", and if the StringContent object is correctly built with the correct media type (x-www-form-urlencoded).

  //gets PayPal accessToken public async Task<ResponseT> InvokePostAsync<RequestT, ResponseT>(RequestT request, string actionUrl) { ResponseT result; // 'HTTP Basic Auth Post' <http://stackoverflow.com/questions/21066622/how-to-send-a-http-basic-auth-post> string clientId = PayPalConfig.clientId; string secret = PayPalConfig.clientSecret; string oAuthCredentials = Convert.ToBase64String(Encoding.Default.GetBytes(clientId + ":" + secret)); //base uri to PayPAl 'live' or 'stage' based on 'productionMode' string uriString = PayPalConfig.endpoint(PayPalConfig.productionMode) + actionUrl; HttpClient client = new HttpClient(); //construct request message var h_request = new HttpRequestMessage(HttpMethod.Post, uriString); h_request.Headers.Authorization = new AuthenticationHeaderValue("Basic", oAuthCredentials); h_request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); h_request.Headers.AcceptLanguage.Add(new StringWithQualityHeaderValue("en_US")); h_request.Content = new StringContent("grant_type=client_credentials", UTF8Encoding.UTF8, "application/x-www-form-urlencoded"); try { HttpResponseMessage response = await client.SendAsync(h_request); //if call failed ErrorResponse created...simple class with response properties if (!response.IsSuccessStatusCode) { var error = await response.Content.ReadAsStringAsync(); ErrorResponse errResp = JsonConvert.DeserializeObject<ErrorResponse>(error); throw new PayPalException { error_name = errResp.name, details = errResp.details, message = errResp.message }; } var success = await response.Content.ReadAsStringAsync(); result = JsonConvert.DeserializeObject<ResponseT>(success); } catch (Exception) { throw new HttpRequestException("Request to PayPal Service failed."); } return result; } 

IMPORTANT: use Task.WhenAll () to make sure you have a result.

  // gets access token with HttpClient call..and ensures there is a Result before continuing // so you don't try to pass an empty or failed token. public async Task<TokenResponse> AuthorizeAsync(TokenRequest req) { TokenResponse response; try { var task = new PayPalHttpClient().InvokePostAsync<TokenRequest, TokenResponse>(req, req.actionUrl); await Task.WhenAll(task); response = task.Result; } catch (PayPalException ex) { response = new TokenResponse { access_token = "error", Error = ex }; } return response; } 
+3
source

We hope that the following code help will help everyone who is still looking for a good piece of cake to connect to PayPal.

Like many people, I spent a lot of time accessing the PayPal token without success, until I found the following:

 public class PayPalClient { public async Task RequestPayPalToken() { // Discussion about SSL secure channel // http://stackoverflow.com/questions/32994464/could-not-create-ssl-tls-secure-channel-despite-setting-servercertificatevalida ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true; ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; try { // ClientId of your Paypal app API string APIClientId = "**_[your_API_Client_Id]_**"; // secret key of you Paypal app API string APISecret = "**_[your_API_secret]_**"; using (var client = new System.Net.Http.HttpClient()) { var byteArray = Encoding.UTF8.GetBytes(APIClientId + ":" + APISecret); client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray)); var url = new Uri("https://api.sandbox.paypal.com/v1/oauth2/token", UriKind.Absolute); client.DefaultRequestHeaders.IfModifiedSince = DateTime.UtcNow; var requestParams = new List<KeyValuePair<string, string>> { new KeyValuePair<string, string>("grant_type", "client_credentials") }; var content = new FormUrlEncodedContent(requestParams); var webresponse = await client.PostAsync(url, content); var jsonString = await webresponse.Content.ReadAsStringAsync(); // response will deserialized using Jsonconver var payPalTokenModel = JsonConvert.DeserializeObject<PayPalTokenModel>(jsonString); } } catch (System.Exception ex) { //TODO: Log connection error } } } public class PayPalTokenModel { public string scope { get; set; } public string nonce { get; set; } public string access_token { get; set; } public string token_type { get; set; } public string app_id { get; set; } public int expires_in { get; set; } } 

This code works very well for me, hoping for you too. The loans are owned by Patel Harshal, who posted his decision here .

+3
source

Paypal is deprecated as TLS 1.1, and only accepts 1.2 now. Unfortunately, .NET uses 1.1 by default, unless you configure it differently.

You can enable TLS 1.2 with this line. I recommend placing it Application_Start or global.asax .

 ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; 
+1
source

I also suffered from a lack of example code and various problems with errors and error codes.

I am a big fan of RestClient, as it helps a lot in integration and the growing number of RESTful API calls.

I hope this little code snippet using RestSharp helps someone: -

  if (ServicePointManager.SecurityProtocol != SecurityProtocolType.Tls12) ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; // forced to modern day SSL protocols var client = new RestClient(payPalUrl) { Encoding = Encoding.UTF8 }; var authRequest = new RestRequest("oauth2/token", Method.POST) {RequestFormat = DataFormat.Json}; client.Authenticator = new HttpBasicAuthenticator(clientId, secret); authRequest.AddParameter("grant_type","client_credentials"); var authResponse = client.Execute(authRequest); // You can now deserialise the response to get the token as per the answer from @ryuzaki var payPalTokenModel = JsonConvert.DeserializeObject<PayPalTokenModel>(authResponse.Content); 
0
source

Source: https://habr.com/ru/post/946365/


All Articles