Development with Ansible and VMs
Published September 11, 2014
This video features Jeff Schenck at DjangoCon US 2015 in Austin, Texas, USA.
REST Easy — API Security Done Right by Jeff Schenck
Why REST
More and more of our web development is shifting to frontend web frameworks like Angular, Ember, and Backbone. And this is great! These frameworks can provide an amazing, responsive, beautiful experience to our users — and the only price we pay is having to write JavaScript. Well, having to write JavaScript and having to maintain a seriously robust, battle-hardened API for the frontend framework to talk to.
State of REST
Django REST Framework has clearly broken away with a ton of momentum, and with good reason. It's a solid framework, and the tools it provides right out of the box — serialization, validation, nested relationships — are splendid. It even provides basic authentication and authorization baked right in, which works great in the very simple cases.
However, when you start encountering slightly more complicated API permission setups, things start to get messy.
REST Security
There's a big tectonic shift when trading in your traditional request-response-Django site for a frontend-framework-API-Django site. Your application logic used to reside almost entirely server-side, but now it's split — half server-side, half browser-side. And the trick with browser-side code is it runs in a completely untrusted environment. So we're faced with a much more complicated security situation to batten down.
You need different authentication strategies: session auth, JWT token auth, API keys, signed URLs, and combinations thereof. You have different permission strategies: table-level, row-level, column-level, and combinations thereof. It gets real complicated.
REST Easy
I'll show how to use the tools at our disposal — Django groups and permissions, REST Frameworks's permission classes, third-party libraries — to cobble together a passable security setup for your API. You'll get plenty of code samples, detailing the kinds of setups we put together for our site and the custom tooling we built to do it.
Next-Level REST
We'll end by talking about how our tools can serve us better in the future. If Django is going to have a strong place in the future of the web, we need strong tooling for building APIs. This is how we'll get there.
Help us caption & translate this video!
REST APIs became more central as JavaScript frameworks moved substantial application logic into the browser, an environment users can manipulate and therefore cannot be trusted. Jeff Schenck explains the authentication and authorization combinations Django REST Framework applications must handle, including endpoint, object, field, and HTTP-method permissions. He argues for small, composable permission classes combined with logical operators such as AND, OR, and NOT, while noting that current tooling scatters rules across viewsets and querysets. He proposes more role-based, centrally defined permissions with a secure default of denying access unless it is explicitly granted.
Summarised automatically from the transcript.
Automatically transcribed, so expect mistakes in names and technical terms.
Thanks. Hi. So thank you so much for being here, for for listening. I'm going to be talking about uh REST APIs here, uh, and specifically uh security of REST APIs and and kind of even more specifically uh authorization authentication within uh your REST API. Um so hopefully that's what you're all interested in. Um there's gonna be a little bit of uh knowledge of of Django Rest framework that's going to be helpful, but hopefully if you haven't gotten a chance to play with it, I'll give you a very quick primer that that hopefully will kind of get you started there. So what are we going to go through today? We're going to talk about why REST. Why is this important right now? Why are REST APIs a big deal?
Why am I talking about them? And why have they changed a little bit in their scope? uh and caused all of these, at least for me, uh security uh considerations. Uh we're gonna talk a little bit about what the state of REST is today. So if you're if you're writing a a Django app and and you want a REST API What do you do? And then we're going to get into security a little bit. Quick overview of kind of the considerations around security, authorization when you're doing a REST API. We're going to talk about some of the strategies that we've come up with to write clear, maintainable permission schemes for your API. And then I'm going to talk a little bit about what I hope happens tomorrow.
And I think our tooling is not quite there yet, and I want to talk about how we might be able to get it there. uh so that we can write really clear, sane, easy uh API permissioning. Um all right, so let's let's get started. Why are we talking about REST? Um and the simple answer is all of these guys. Um Angular, Backbone, Ember, and so on have just exploded in popularity in the last couple of years. Um You know, and there's there's there's all this growth. They're really taking over a big chunk of what we do as what you know as web developers. Um and so you know the more nuanced answer there then is I want to talk a little bit about kind of the the pieces of your app,
what's running where and where these new JavaScript frameworks come into play and how that changes the game a little bit. So uh you can break down your application into three basic components uh very roughly. Uh display logic. right, which is happening traditionally on the browser, uh app logic, which is kind of what's running your app, and then data stores. Um and the traditional way that you know historically these have been been broken broken out is the display logic happens on the front end or in the browser, right? Pretty straightforward. And then your application logic and the data stores and all that all lives on the server, the back end. And you know, historically we've used HTML, CSS, and JavaScript to talk uh to the browser, and then the browser posts some some HTML form.
uh back to the server and it all worked really well until we wanted to do more things in the browser, right? And we came up with this Ajax thing and we sort of shoehorned it in there Um and that worked fairly well for a while and things grew and grew. Um and we started doing more and more f of the application logic. On the front end in the browser, right? Um and this is really, you know, with with Angular and Backbone and so on. Uh That's where this really kind of came into its own, is huge portions of what was uh what's your you know your app logic, which traditionally lived on a server, is now happening in the browser, right? Um and it turned out that AppLogic needed to sit a little closer to your data, right?
And so we came up with, or you know, it'd been around for a little while, but uh we started using REST really heavily. to shuttle that information back and forth at a at a lower level uh between the front end and the back end because you're doing all of this app logic in the front end. So um let's start talking about how we do that today, uh the state of rest today. Um this is just Google Trends, which is you know uh Take it for what it is, but uh the blue line there is Django Rest framework. Um the other two lines are Piston and Tasty Pie. Um I think there's a couple of interesting things to note about this graph. One is Django Rest Framework seems to be the clear winner of this crew at this point, and it's really only happened in the last couple of years.
I think there's a huge community around this now, and there's a lot of tooling around it, which is great. The other thing to note about this graph is Just the magnitude in general, right? All three combined, it's really exploded in the last year or two. Um so this is this is, you know, to me this says this stuff's pretty important and growing in importance. So I want to give you a real brief overview of what Django Rest Framework uh gives to you, just so you get the ecosystem a little bit. There's serializers which help you translate your Django models, your data, uh into a representation to be sent down over the wire, so JSON, XML, that sort of thing, and to be re-inflated on the way back. Um there's views
which kind of connect up uh the a query set, so your data, with that serializer, and then you connect that to an endpoint, you conserve uh in this case cats at uh at a given URL for your API. Um it comes with a bunch of authentication stuff. So it comes with a bunch of built-in ones. There it's pluggable, so you can down, you know, you can pip install some other ones. Um But there's a really you know pretty straightforward framework for adding authentication into your API uh and then permissioning and we'll we'll dive a little bit deeper into those too uh the rest of this this talk. Um Cool. So let's talk about security, uh authorization, authentication, in
in the context of this REST API. Um so you remember this diagram where uh app log you know the front end the browser was swallowing up your app logic. Uh there's another important way to think about this, I think, which is A lot of your app logic is now running in this insecure browser environment, right? If you think about it Uh we've been able to rely on the server being, you know, presumably secure, right? That code there, you know you wrote it. You know what's running. The browser not so much, right? The browser anyone can do anything. A nefarious agent can you know mess with whatever they want. And as soon as we started doing more of the app logic in the browser
And getting closer to the data store, it opened up a lot of new security issues that I think that we, you know, we don't have a lot of practice uh working with as web developers working in in Django more, you know the historically the way Django's worked. So there's some new concepts to sort of wrap your head around here and some new security issues to be aware of. Alright, so I want to go quick overview of the kinds of authentication just to give you a sense of like what's involved here, right? Why is this such a big problem? It's sort of an n squared, n cubed problem because there's so much going on Um uh authentication, right? There's a lot of different ways to authenticate. Many of these are built in. Some of them you can you can pip install like I mentioned. You've got HTTP basic off, Django
Session off. Token auth, OAuth, JSON Web Token Auth. There's a lot of different mechanisms that you can install to do authentication. And the key here is probably most of these web apps are not using just one. Right. So uh you know you might use Django Session Auth as kind of your main authentication format. But then also if you're gonna do a password reset, there's a token there and that's a different kind of authentication. And maybe you want users to sign up with Facebook and then that's another kind of authentication. And suddenly you've got all these different levels of authentication that you have to deal with and cross-reference with all the different kinds of permissions that you care about, right? And there's a lot of these as well. So You can have table level permissions, right?
Can you access the cats or not? There's row level permissions, right? Is this your cat or is this someone else's cat? And what does that mean for your permissions? There's column level permissions, so uh as much as we love cats, let's talk about you know the user model, right? You might want your users to be able to set their name, right? Change their name in in in uh your website, but you probably don't want them to be able to set the super user flag, right? Um and so suddenly you've got these column-level permissions where you have to say these kinds of users with these kinds of authentications should be able to touch these uh these columns, not these columns. Um and then HTTP verb permissions, which roughly analogous to read, write uh and that sort of thing, read, write, delete.
You know, and so you know like I was saying all of these things combine and you start to get this n squared or n cubed problem because there are other other factors you need to take into account. where there are a lot of different combinations, a lot of different situations that you need to account for and it gets messy really, really quickly if you're not careful. Um so let's talk a little bit about how we do a good job of this today. What tools do we have at our disposal today? uh to to you know put some order into this and and to make it maintainable, make it sane So the first and and really the biggest concept that that I want you all to understand and take back and implement is small composable permissions. Um take those permission classes in Django
REST framework and make them as small and focused as possible. And you'll see later we're going to use we're going to we're going to use a tool to kind of compose those into more complicated permissions. So uh you might have some uh HTTP verb permissions, right? So we can create one called isPost, uh subclass the permission class. And then has permission, this function that says, you know, does this person have this permission? Really just checks, is this a post? And that's it, right? On its own, pretty much useless probably, but when we start composing it with other things, you'll see the power of this. And then so you might have one for ispatch , you might have one for all the HTTP verbs, right?
And then these become tools in your tool chest that you can apply to more complex permissioning problems. Let's look at user status. You might have an is authenticated permission, right? And this one That has permission, uh, just checks are you authenticated? There you go. Simple, easy to unit test, easy to think about, easy to reason about, um, and they'll come together in really powerful ways a little later You might have one for is super user that checks the superuser flag. And then you know all the other authentication methods, right? So you'd go on and on and on. So you know if you have Facebook authentication, you'd have some of these for Facebook. If you have that URL token as an authenticator, you'd have one of these for that, right?
Just really simple checks. You're going to do the same thing potentially for ownership. Right? Are you the owner of this cat? And there's a little bit of a caveat here. The way that Django Rest framework is set up, it's really hard to do this check in the has permission like you would want Right, so for list level permissions, getting a bunch of cats, for example, you really end up having to implement that in the get query set method uh on the view, uh on the view set. Um Which is which is one of the things that we're going to talk about, hopefully making better uh in the future. Um but then you see the has object permission Um which where you can kind of define does this user have permission to touch this object?
Um is pretty straightforward, right? Uh are you is this request user the owner of this cat object There you go. And again, you'll do this for all of the different components in your application that you care about. Alright, so to put it all together, we need a couple more power tools. The first is a field restriction helper. Um and I'll walk you through this. Uh but basically what we want out of this is, you know, I remember I mentioned If you want your users to be able to set their name on their account, but you don't want them to be able to set the superuser flag, uh, this is how we're going to accomplish that sort of thing, right? We're going to it's basically it ends up being a uh a class constructor or a class factory.
Um I've capitalized this to make it look like a class, and I think that looks nice in the final product. But technically this is a function. If that bugs you when you do this, you can go ahead and name it lowercase. But yeah, so you're going to have a function that takes a set of fields, right? So like the name field, but not the superuser field. And what it's going to do is it's going to construct that permission class for you on demand. It's going to create a set out of the fields and save that for later. And then that permission class, when it uh gets asked, does the user have permission, it's just gonna say, hey. Uh all the fields that you're talking about in this request, are they a strict subset of the allowable fields that this was created with?
Right. So you can say, you know, if you pass in, you know, you do an is fields and you pass in just the name field, then anyone who ever tries to touch the super user flag will get denied by this permission. Right. Um and you do essentially the same thing under the has object permission. Uh and then you return the permission class. Awesome. So now we can restrict the columns that you're accessing. This is a a tool that, you know, as you can see, this is a a basic version of it. relatively straightforward to put together yourself, but it's also something that you know we've written and we'd like to open source, so hopefully we can do that soon for you guys. You know, we'd love more batteries to be just out there and ready to use. So the last power tool we need is this thing called REST Condition.
So you can pip install RESTCondition, and this is really the crux of everything, right? uh it gives you these composers, these ands and ors and nots that you use to put these pieces together into more complicated permissions, right? So you could combine two things with an OR and you could describe a permission as if you have foo perm and not barperm or if you have basperm Then you have this permission, right? And so let me show you an example of how we build a relatively complex permission structure out of these tiny pieces and this rest condition stuff. So uh we've got a a view set here, right? We're gonna view some cats.
Um it's gonna have a lot of other stuff. If you've written Django Rest framework stuff, this will have you know this view set will have lots of other things defined in it, but What we care about is this permission classes , where we're defining it at a base as this OR. And this is a pattern that you'll uh end up repeating again and again. The base is just Oring together a bunch of different sets of permissions. You know, different kinds of people have different kinds of access, and that's what you're describing here. So for example, this first one is if you if it's a get header option, so if effect you know effectively read-only, uh and you're an authenticated user, great, you're good to go. Or If it's a post or a patch and you're the owner of the cat and you're only touching the hair or grumpiness level, then you're good to go.
Or if you're a super user, you can just do whatever you want. Right. And so you can see this is, you know, it's not sh totally short, it's not totally easy, but it's a lot less messy and a lot less complicated than the alternative, which is writing all of those things again and again for every view set, right? For every set of permissions. So these kinds of composable things and and you know it makes it much more readable, much more maintainable to have these things as kind of composable base permission class. Alright, so let's talk a little bit about uh the world of tomorrow, right? How can the world be better uh if we were to Uh, if we were to build some tooling around this.
Um so let let's first give a quick overview of kind of the problems that exist here. So there are a few a few things that I think still plague us, even with even with these kind of small composable permissions. One is everything's endpoint based, right? We defined this on the viewset class, right? Which roughly analogous to an endpoint, the cat 's endpoint of your API, right? Um, I think the the s the the easier way to reason about this stuff is to have it be role-based, right? Role-based permissions. So if you are a super user, here's your list of permissions. If you're a cat owner, here's your list of permissions. And then those all get combined, but they get defined at a role-based level, right? Much easier to reason about.
Another thing that plagues us is this code is still scattered, right? You saw we've got uh has permission, we've got has object permission. Some of it had to go in get query set , and it's still scattered throughout every single view set definition, all of those little composable permissions. It's in lots of different places And centralizing all the permission code in one common place , I think would help a lot in kind of reasoning about it, right? If it's all the right there. As I mentioned, batteries aren't entirely included here. A lot of the authentication schemes are. But you know that that is field thing. Um there are a lot of other pieces of this that we've had to write internally.
We're working to open source those, but in the meantime, right, these batteries are not really included. And the default is confusing, right? Do you default have permission or not have permission? The more secure option is default? No. You don't have permission. Uh but the way this is working, it's sort of confused. In some c in some ways it's one and in some ways it's the other. And I think it'd be helpful to just standardize No one has any permissions unless you explicitly say so, right? So uh I want to tease, you know, imagine imagine what this might look like. This is a you know none of this code has been written underneath the c you know None of the the code that would actually run this has been written, but I want to give an example of maybe what this might look like, right?
Uh just to kind of tease the idea and hopefully if anyone here is interested in this, I'm gonna be Spending the rest of the week hacking on this and trying to get something together. If you're interested in helping out, I'd love your help. I'd love to make this this a better, you know, a better situation for everybody. Um but This is sort of a V1 idea of what the world could look like, right? You're defining a role-based permission, so anonymous user here, right? You're telling me is it active, right? For this request, uh, is this role active? And then you just define the permissions there, right? So in this case for the uh cat endpoint you can list or retrieve, but because it's default no permissions, you can't post, you can't patch, you can't delete.
Right. And this would go on, of course, for for other permissions. Uh and you'd go on and define other roles as well. So there's a lot of nuance that isn't included here. There's a lot uh that still needs to be figured out and the how the kind of the way this would be implemented. Um but I think making this uh this whole ecosystem a lot easier to reason about, easier to maintain, is gonna plug up some serious security holes. I know, you know, we even with these composable permissions We've had security polls. And I want to save people from that. I think that's, you know, partly our fault, right? We wrote the code. But partly the fault of the tools, right? The tools weren't helping us write secure code. So that's what I want for us. And like I said, if you are interested in helping, come find me.
So thanks so much. I'm Jeff. I have to give a quick plug to Choose, because they paid for me to be here So if you know anyone in San Francisco who uh wants better lunches at work, let us know. Um and yeah, that's it. Thanks so much.
JavaScript frameworks such as Angular, Backbone, and Ember move much of the application logic into the browser. REST APIs provide a low-level way for that front end to exchange data with the server and its data stores.
Discussed at 4:09It provides serializers for converting Django data to and from formats such as JSON, views for connecting querysets to serializers and endpoints, and pluggable authentication and permission systems.
Discussed at 4:59The browser is an untrusted environment where a malicious user can alter client-side logic. As more application logic moves there and gets closer to the data store, APIs need explicit authentication and authorization controls, including table-, row-, field-, and HTTP-verb-level permissions.
Discussed at 6:33Use small, focused permission classes that each perform one simple check—such as the HTTP verb, authentication status, superuser status, or ownership—and compose them into larger rules. REST Condition supplies logical AND, OR, and NOT operators for combining those pieces.
Discussed at 9:40Create a field-restriction permission that receives the allowed fields and denies requests containing any fields outside that set. For example, users can be allowed to update their name while being prevented from changing the superuser flag.
Discussed at 13:37Permissions should be defined centrally by role rather than scattered across individual endpoints, with roles such as superuser or cat owner receiving explicit permission lists. The safer default should be that users have no permissions unless they are granted explicitly.
Discussed at 17:30Note: We understand that names change, people change, and bodies change. We respect each individual's journey and privacy. If you have any concerns about a video or need us to remove content, please don't hesitate to contact us. We will handle your request with care and promptly address any issues.
Published July 15, 2026
Published July 15, 2026
Published July 15, 2026
Published July 15, 2026
Published July 15, 2026
Published July 14, 2026