Skip to content

Instantly share code, notes, and snippets.

@jsdevtom
Last active April 7, 2023 17:55
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Embed
What would you like to do?
The solution to getting Paypal's verify endpoint to work was to serialize JSON manually like so:
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
namespace server.Payment
{
public class PaymentController : Controller
{
private static readonly HttpClient client = new HttpClient();
[HttpPost("api/checkout/webhook")]
[AllowAnonymous]
public async Task<IActionResult> HandleWebhook()
{
var json = await new StreamReader(HttpContext.Request.Body).ReadToEndAsync();
var headers = HttpContext.Request.Headers;
await VerifyEvent(json, headers);
// handle etc...
return Ok();
}
private async Task VerifyEvent(string json, IHeaderDictionary headerDictionary)
{
var bearerToken = await Authenticate();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken);
// !!IMPORTANT!!
// Without this direct JSON serialization, PayPal WILL ALWAYS return verification_status = "FAILURE".
// This is probably because the order of the fields are different and PayPal does not sort them.
var paypalVerifyRequestJsonString = $@"{{
""transmission_id"": ""{headerDictionary["PAYPAL-TRANSMISSION-ID"][0]}"",
""transmission_time"": ""{headerDictionary["PAYPAL-TRANSMISSION-TIME"][0]}"",
""cert_url"": ""{headerDictionary["PAYPAL-CERT-URL"][0]}"",
""auth_algo"": ""{headerDictionary["PAYPAL-AUTH-ALGO"][0]}"",
""transmission_sig"": ""{headerDictionary["PAYPAL-TRANSMISSION-SIG"][0]}"",
""webhook_id"": ""<get from paypal developer dashboard>"",
""webhook_event"": {json}
}}";
var content = new StringContent(paypalVerifyRequestJsonString, Encoding.UTF8, "application/json");
var resultResponse = await client.PostAsync("https://api-m.sandbox.paypal.com/v1/notifications/verify-webhook-signature", content);
var responseBody = await resultResponse.Content.ReadAsStringAsync();
var verifyWebhookResponse = JsonConvert.DeserializeObject<VerifyWebhookResponse>(responseBody);
if (verifyWebhookResponse.verification_status != "SUCCESS")
{
throw new Exception("failed to verify webhook response");
}
}
private async Task<string> Authenticate()
{
// TODO: make all hard coded values configurable
var request = WebRequest.Create("https://api-m.sandbox.paypal.com/v1/oauth2/token");
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.Headers.Add("grant_type", "client_credentials");
var postData = "grant_type=client_credentials";
var byteArray = Encoding.UTF8.GetBytes(postData);
var dataStream = request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = byteArray.Length;
var clientId = "<get from paypal developer dashboard>";
var clientSecret = "<get from paypal developer dashboard>";
var encoded = Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1")
.GetBytes(clientId + ":" + clientSecret));
request.Headers.Add("Authorization", "Basic " + encoded);
try
{
var response = await request.GetResponseAsync();
using (dataStream = response.GetResponseStream())
{
var reader = new StreamReader(dataStream);
var responseFromServer = reader.ReadToEnd();
Console.WriteLine(responseFromServer);
var token = JsonConvert.DeserializeObject<TokenResponse>(responseFromServer);
return token.access_token;
}
}
catch (WebException e)
{
string content;
using (var reader = new StreamReader(e.Response.GetResponseStream()))
{
content = reader.ReadToEnd();
Console.WriteLine("content", content);
}
throw;
}
}
}
}
@itfm
Copy link

itfm commented Jul 21, 2022

What does VerifyWebhookResponse look like or where can I find a sample response from PayPal?

@HenryBJ
Copy link

HenryBJ commented Aug 4, 2022

@itfm It must look like this:

{
  "verification_status": "SUCCESS"
}

@HenryBJ
Copy link

HenryBJ commented Aug 4, 2022

@jsdevtom Thanks for your help bro !!!

@jsdevtom
Copy link
Author

jsdevtom commented Aug 8, 2022

@HenryBJ You're very welcome

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment