Securing your webhooks - GitHub Docs GitHub Docs All products Developers Overview About GitHub's APIs Managing deploy keys Viewing deployment history Using SSH agent forwarding Secret scanning Replacing GitHub Services GitHub Developer Program Webhooks and events Webhooks About webhooks Creating webhooks Configuring your server to receive payloads Testing webhooks Securing your webhooks Webhook events and payloads Events GitHub event types Issue event types Apps Getting started with apps About apps Activating beta features for apps Differences between GitHub Apps and OAuth Apps Migrating OAuth Apps to GitHub Apps Setting up your development environment to create a GitHub App Building GitHub Apps Creating a GitHub App Setting permissions for GitHub Apps Authenticating with GitHub Apps Identifying and authorizing users for GitHub Apps Rate limits for GitHub Apps Refreshing user-to-server access tokens Creating a GitHub App from a manifest Creating a GitHub App using URL parameters Creating a custom badge for your GitHub App Managing GitHub Apps Installing GitHub Apps Modifying a GitHub App Editing a GitHub App's permissions Making a GitHub App public or private Suspending a GitHub App installation Transferring ownership of a GitHub App Deleting a GitHub App Building OAuth Apps Creating an OAuth App Authorizing OAuth Apps Scopes for OAuth Apps Creating a custom badge for your OAuth App Managing OAuth Apps Modifying an OAuth App Transferring ownership of an OAuth App Troubleshooting authorization request errors Troubleshooting OAuth App access token request errors Deleting an OAuth App Guides Using the GitHub API in your app Using content attachments Creating CI tests with the Checks API GitHub Marketplace GitHub Docs Explore by product Developers GitHub.com Enterprise Administrators GitHub Discussions GitHub Actions GitHub Packages Developers REST API GraphQL API GitHub Insights Education GitHub Desktop GitHub CLI Atom Electron English English 简体中文 (Simplified Chinese) 日本語 (Japanese) Español (Spanish) Português do Brasil (Portuguese) Article version: GitHub.com GitHub.com Enterprise Server 3.0 Enterprise Server 2.22 Enterprise Server 2.21 Enterprise Server 2.20 GitHub AE See all Enterprise releases Developers Webhooks and events Webhooks Securing your webhooks Article version: GitHub.com GitHub.com Enterprise Server 3.0 Enterprise Server 2.22 Enterprise Server 2.21 Enterprise Server 2.20 GitHub AE See all Enterprise releases Securing your webhooks Ensure your server is only receiving the expected GitHub requests for security reasons. In this article Setting your secret token Validating payloads from GitHub Once your server is configured to receive payloads, it'll listen for any payload sent to the endpoint you configured. For security reasons, you probably want to limit requests to those coming from GitHub. There are a few ways to go about this--for example, you could opt to allow requests from GitHub's IP address--but a far easier method is to set up a secret token and validate the information. You can use the repository, organization, and app webhook REST APIs to create, update, delete, and ping webhooks. You can also use the REST API to change the configuration of the webhook. For example, you can modify the payload URL, content type, SSL verification, and secret. For more information, see: Repository Webhooks REST API Organization Webhooks REST API GitHub App Webhooks REST API Setting your secret token You'll need to set up your secret token in two places: GitHub and your server. To set your token on GitHub: Navigate to the repository where you're setting up your webhook. Fill out the Secret textbox. Use a random string with high entropy (e.g., by taking the output of ruby -rsecurerandom -e 'puts SecureRandom.hex(20)' at the terminal). Click Update Webhook. Next, set up an environment variable on your server that stores this token. Typically, this is as simple as running: $ export SECRET_TOKEN=your_token Never hardcode the token into your app! Validating payloads from GitHub When your secret token is set, GitHub uses it to create a hash signature with each payload. This hash signature is included with the headers of each request as X-Hub-Signature-256. Note: For backward-compatibility, we also include the X-Hub-Signature header that is generated using the SHA-1 hash function. If possible, we recommend that you use the X-Hub-Signature-256 header for improved security. The example below demonstrate using the X-Hub-Signature-256 header. For example, if you have a basic server that listens for webhooks, it might be configured similar to this: require 'sinatra' require 'json' post '/payload' do push = JSON.parse(params[:payload]) "I got some JSON: #{push.inspect}" end The intention is to calculate a hash using your SECRET_TOKEN, and ensure that the result matches the hash from GitHub. GitHub uses an HMAC hex digest to compute the hash, so you could reconfigure your server to look a little like this: post '/payload' do request.body.rewind payload_body = request.body.read verify_signature(payload_body) push = JSON.parse(params[:payload]) "I got some JSON: #{push.inspect}" end def verify_signature(payload_body) signature = 'sha256=' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), ENV['SECRET_TOKEN'], payload_body) return halt 500, "Signatures didn't match!" unless Rack::Utils.secure_compare(signature, request.env['HTTP_X_HUB_SIGNATURE_256']) end Your language and server implementations may differ from this example code. However, there are a number of very important things to point out: No matter which implementation you use, the hash signature starts with sha256=, using the key of your secret token and your payload body. Using a plain == operator is not advised. A method like secure_compare performs a "constant time" string comparison, which helps mitigate certain timing attacks against regular equality operators. Did this doc help you? Privacy policy Want to learn about new docs features and updates? Sign up for updates! We're continually improving our docs. We'd love to hear how we can do better. What problem did you have? Required Choose an option Information was unclear The content was confusing The article didn't answer my question Other Let us know what we can do better Optional Can we contact you if we have more questions? Optional Send Thank you! Your feedback has been submitted. Help us make these docs great! All GitHub docs are open source. See something that's wrong or unclear? Submit a pull request. Make a contribution Or, learn how to contribute. Still need help? Ask the GitHub community Contact support © 2021 GitHub, Inc. Terms Privacy Security Status Help Contact GitHub Pricing Developer API Training About