I\'m trying to call Paypal api from my code. I set up the sandbox account and it works when I use curl but my code isn\'t working the same way, returning 401 Unauthorized instea
This Works using HttpClient... 'RequestT' is a generic for the PayPal request arguments, however it is not used. The 'ResponseT' is used and it is the response from PayPal according to their documentation.
'PayPalConfig' class reads the clientid and secret from the web.config file using ConfigurationManager. The thing to remember is to set the Authorization header to "Basic" NOT "Bearer" and if and to properly construct the 'StringContent' object with right 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 ensure 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;
}
Paypal has deprecated TLS 1.1, and only accepts 1.2 now. Unfortunately .NET (prior to version 4.7) uses 1.1 by default, unless you configure it otherwise.
You can turn on TLS 1.2 with this line. I recomend placing it Application_Start
or global.asax
.
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
Hoping the following code help to anyone who is still looking for a good piece of cake to get connected to PayPal.
As many people, I've been investing a lot of time trying to get my PayPal token access 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 pretty well for me, hoping for you too. The credits belong to Patel Harshal who posted his solution here.
I too suffered from a lack of example code and various issues with response errors and codes.
I am a big fan of RestClient as it helps a lot with integrations and the growing number of RESTful API calls.
I hope this small snippet of code 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);