How to validate web requests in Django using a shared secret

I was talking to one of the guys in my co-working space the other day. He’s learning Python and building a backend for a mobile app that sends JSON data to a web service endpoint he has built using Django. The issue he was running into was how to validate that the requests were actually coming from his app. This post explains how to do it with a shared secret.

Restricting access to views

Let’s say you have a Django view function that looks something like this.

Notice how you are using the require_http_methods  decorator to restrict the allowed HTTP methods to POST. If somebody makes a non-POST request to this view, Django will return a 405 status code.

Verifying requests using HMAC

You can use a HMAC (hash-based message authentication code) to make sure that (1) the sender of the message has the shared secret, and (2) that the message contents has not been tampered with.

There are two inputs to the HMAC function: the shared secret, or the “key”, and the message itself, which for us is the body of the HTTP request. The hash function is SHA256. The Base-64 encoded HMAC can then be sent as a HTTP header and used on the receiving end to verify the message.

In this case, the HMAC is sent in the “X-MY-APP-HMAC” header. The following piece of code extends the Django view function to validate the request, assuming the shared secret is stored in your Django settings file at myapp.settings.MY_APP_SHARED_SECRET .

The 401 HTTP status code is used when some authentication has not been provided, so you can use it here to tell the client that the request has been denied because of the invalid HMAC.

Wrapping it up in a decorator

The code above will work fine, but it’s a bit messy. What if you have multiple views that need to verify their requests? You would end up copying and pasting code. You could move the verification code out to a function and call it first thing, but a much better option is to turn it into a decorator.

Then you can simply decorate your view function like so:

Remember that decorators get executed from the inside out, so the require_http_methods  decorator will get called before validate_request_hmac .

That’s it. How to generate requests with the proper headers on the sender’s side depends on the platform. I’ll leave it as an exercise.