Skip to content

Instantly share code, notes, and snippets.

@categulario
Created June 23, 2014 15:15
Show Gist options
  • Save categulario/deeb41c402c800d1f6e6 to your computer and use it in GitHub Desktop.
Save categulario/deeb41c402c800d1f6e6 to your computer and use it in GitHub Desktop.
Validate GitHub signature in python
# validate github signature
import hashlib
import hmac
import json
signature = hmac.new(GITHUB_TOKEN, payload, hashlib.sha1).hexdigest()
# assuming that the 'payload' variable keeps the content sent by github as plain text
# and 'headers' variable keeps the headers sent by GitHub
if hmac.compare_digest(signature, headers['X-Hub-Signature'].split('=')[1]):
payload_object = json.loads(payload)
# do something here
return json.dumps({'msg': 'Done!'})
else:
return json.dumps({'msg': 'not a chance'})
@captain-kark
Copy link

captain-kark commented May 27, 2019

I was setting up a unit test for this function and realized that github's payload comes in minified. Edit: so if you want to include a mock payload in a unit test file somewhere, you either need to paste it in as-is on a single line. Alternatively, you can parse it, and then dump it back out with separators that result in the same minified json.

mock_payload_body = """{
  "action": "closed",
  "issue": {
    "url": "https://api.github.com/repos/Foo/bar/issues/1",
    "repository_url": "https://api.github.com/repos/Foo/bar",
    ...
}"""

minified_payload_body = json.dumps(json.loads(mock_payload_body).separators=(',',':')

# for python3.7
signature = hmac.new(
    secret.encode(),
    json.dumps(minified_payload_body).encode(),
    hashlib.sha1
).hexdigest()

@webknjaz
Copy link

webknjaz commented Feb 5, 2020

@captain-kark you're not supposed to parse the payload and dump it back. You have to validate the exact bytes that you get in the HTTP request body.

@captain-kark
Copy link

I do that, when receiving payloads from github in live environments.

What I'm referring to here is reversing this process for a unit test. I updated my comment to include these details, the way I worded it was confusing.

@webknjaz
Copy link

webknjaz commented Feb 6, 2020

👍 Well, technically you don't really have to minify anything. Because you're signing the HTTP request body, you just need to ensure that what you sign is exactly what's in the body.

@ddabberu
Copy link

ddabberu commented Aug 14, 2020

If using flask service, just get the raw body as bytes (request.data), no need to do json.dumps or anything and encode the payload, or minify, it'll work.

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