#ague_webhooks-go

1 messages ยท Page 1 of 1 (latest)

carmine atlasBOT
#

๐Ÿ‘‹ Welcome to your new thread!

โฒ๏ธ We'll be here soon! Typically we respond in a few minutes, but sometimes we might take a bit longer if the server is busy or if you have a particularly tricky question.

โฑ๏ธ We close idle threads, which makes them read-only. Once a thread is closed it won't be reopened, but you can always start a new thread if you have another question.

๐Ÿ”— This thread will always be available, even after it's closed. You can find it again using Discord's search, or you can save this link: https://discord.com/channels/841573134531821608/1215428816076283985

๐Ÿ“ Have more to share? Add more details, code, screenshots, videos, etc. below.

pulsar siloBOT
pale summit
#

๐Ÿ‘‹

tardy vigil
#

Hi there! Note that webhook signatures for use with the CLI and on the Dashboard are different

pale summit
#

I know. I realized that and moved from CLI to Dashboard so I didn't have to keep updating my secret in AWS Secrets

#

but nevertheless, the problem persists. I've revealed the secret in the dashboard, verified that I am using the correct secret. In a last ditch effort, I dumped all variables involved to logs and thats when I saw that I'm only receiving [INFO]: t=1709849877 when calling

sigHeader := r.Header.Get("Stripe-Signature")
log.Infoln(sigHeader)

Based on everything I have read and recall from last time I setup v72, I'm supposed to get a hash in a v0 and v1 portions of the header. Which I'm not receiving

tardy vigil
#

Can you share your handler code, specifically how you're constructing the event?

pale summit
#

sure. one sec

#
func HandleWebhook(w http.ResponseWriter, r *http.Request) {
    if r.Method == http.MethodOptions {
        return
    }

    w.Header().Set("Content-Type", "application/json")

    const MaxBodyBytes = int64(65536)
    r.Body = http.MaxBytesReader(w, r.Body, MaxBodyBytes)
    body, err := io.ReadAll(r.Body)
    if err != nil {
        w.WriteHeader(http.StatusBadRequest)
    _, _ = w.Write([]byte{})
    return
    }

    sigHeader := r.Header.Get("Stripe-Signature")
    //sigSplit := strings.Split(sigHeader, ",")
    
    // Secret is pulling correctly from AWS secrets
    event, err := webhook.ConstructEvent(body, r.Header.Get("Stripe-Signature"), Secret)
    if err != nil {
    w.WriteHeader(http.StatusBadRequest)
    _, _ = w.Write([]byte{}) // TODO: More informative HTTP responses
    return
    }

    // process wh event

    w.WriteHeader(http.StatusOK)
}
#

it's mostly just copied from the docs

#

I also removed my log lines for brevity

tardy vigil
#

I'll run this by a teammate who's more well versed with Go but I suspect it may have to do with this line:
r.Body = http.MaxBytesReader(w, r.Body, MaxBodyBytes)

pale summit
tardy vigil
#

Oh, you're right ๐Ÿ˜… Hence why I'm checking in with a teammate

#

Hang tight!

pale summit
#

no worries, I'll be here

pulsar siloBOT
pale summit
#

๐Ÿ‘‹

glass moss
#

ague_webhooks-go

#

๐Ÿ‘‹ Sorry I know basic go myself but not much more. Happy to help though

pale summit
#

sure

glass moss
#

Step 1: you mentioned the secret, which one are you using? The CLI has its own secret so they work completely differently

pale summit
#

the last secret I used was a dashboard secret with a dashboard fired test event

#

assuming you can see things on my account, it's the one attached to the wh endpoint listed in my original request

glass moss
#

Okay so right now the CLI is fully off and you have a real public API endpoint that is receiving that specific Event?

pale summit
#

yes, I still have a prod endpoint that receives webhooks properly from v72. I'm working on upgrading to the latest sdk across the board

#

and the endpoint receiving my test webhooks now is a lambda function

glass moss
#

is this brand new code that lambda function? Or is it exactly what you have set up in the past on v72?

pale summit
#

it's the same. I noticed things didn't seem to have changed all that much between versions when I was going over the latest docs

glass moss
#

Okay so you created a brand new WebhookEndpoint, pinned to the latest API version, then you deployed code that received the Event the exact same way your existing production endpoint works and you're getting a signature mismatch?

pale summit
#

I'm getting webhook had no valid signature specifically

#

but, yes, everything else is as you said. I'm receiving the webhook into my lambda function, but signature validation fails

glass moss
#

Cool, can you do this again but log the exact signature and exact webhook secret first? Share the last 4 characters of both so I can confirm they match

pale summit
#

fire a new event or resend a previous one?

#

Event: evt_1Orq7GGniDWbO48M5OcRHptf
Secret last 4: 3r06
Signature v1: df30
Signature v0: 398a

glass moss
#

Okay so you have all the right values

pale summit
#

which makes me even more confused

glass moss
#

So the problem has to be with the code itself and how you extract the "raw body" from the incoming request. Something, somewhere, no idea what yet, is likely extracting the info incorrectly which prevents us from verifying the signature since we have a different body/payload

#

Can you log the raw data you are receiving to a file and then share it so I can have a look?

pale summit
#

raw data from the incoming webhook?

#

also, I'm using go 1.22. I saw that the sdk is using 1.13. perhaps it's a language version issue?

glass moss
#

unlikely but possible yes

#

how easy is it for you to switch to v72 on that exact code and see if the signature matches?

pale summit
#

um, not terribly difficult. will take me a few minutes

glass moss
#

that'd help understand if it's the SDK or your environment

#

I want to believe it's something in the way you configured the lambda

pale summit
glass moss
#

hum you have no "indentation" here which surprises me and is likely the issue

#

like there's no "space" before properties

#

that looks like something is changing the content of what we send to you

pale summit
#

sorry, had to hand copy it from Coudwatch... AWS does evil things to Go logs in CloudWatch

glass moss
#

Ah yeah. Hum verifying the signature is extremely tricky. It has to match exactly what we sent you, up to any space and comma

#

So you need to find a way to log the exact raw text otherwise we can't make progress. What I do is write it to a file when I debug this

pale summit
#

the headers is a raw header dump

#

ok, gimme a couple minutes.. I'll add some extra code to dump to a file

glass moss
#

sounds good

pale summit
#

ok, before I go the route of hacking out a file, I reverted with the exact same code to v72 and still receiving the same error. but I think the dashboard still sent me a v76 webhook. I don't know how to fire a webhook off for a specific api version from the dashboard

glass moss
#

that's mostly impossible

#

but you'd get a different error if the issue was the API version

pale summit
#

makes sense

#

same error as before, though

glass moss
#

okay so at least this seems to confirm this isn't an SDK issue and it's something in your own environment that's causing it

#

I assume you have some kind of CDN for example that is in front of your endpoint and it's doing "something" to the raw body. And your production environment must have a specific configuation

pale summit
#

it's being proxied through aws api gateway. guess I'll have to take a closer look at what's going on there even though proxying the way I am is supposed to just pass through the body as is

glass moss
#

yeah my understanding is that some gateways will parse the JSON to be helpful

#

A few years ago some developers said they had to write a custom "Body Mapping Template" that looked like this { "method": "$context.httpMethod", "body": $input.json('$'), "rawBody": "$util.escapeJavaScript($input.body).replaceAll("\\'", "'")", "headers": { #foreach($param in $input.params().header.keySet()) "$param": "$util.escapeJavaScript($input.params().header.get($param))" #if($foreach.hasNext),#end #end } }

#

my guess is you have something like that in prod

pale summit
#

my prod is not running serverless

#

I'm trying to move that way, tho

glass moss
#

ah I asked earlier if you had the exact same set up in prod and you said yes

#

So yeah I think that's what is biting you right now

pale summit
#

sorry, thought you were referring to code

#

anyways, thank for your time and help. guess I have to fight with AWS some more. also came across this and will look at it as a possibility for the future