Making security more accessible for developers, with Sam Scott, co-founder and CTO of Oso

Sam Scott, Beyang Liu

How do you make security, a topic that often requires a PhD to understand, accessible to your average developer? In this episode, Sam Scott, co-founder and CTO of Oso, a batteries-included library for building authorization into your application, comes on the podcast to explain to Beyang Liu, CTO at Sourcegraph, his vision for the future of security development. Along the way, Sam also shares how he got started in cryptography, explains why they pivoted Oso from infrastructure to application authorization, and shows Beyang how you can use Oso to build an authorization model with just 26 lines of code.

Click the audio player below to listen, or click here to watch the video.

Show Notes

Oso: https://www.osohq.com/

Oso YouTube channel: https://www.youtube.com/channel/UCrDCuHLJ32Cn0-j9K6wMwAg/videos

Oso community Slack: https://join-slack.osohq.com/

The Polar Language: https://docs.osohq.com/rust/learn/polar-foundations.html

Go: https://golang.org/

GitClub: https://github.com/osohq/gitclub

Typescript: https://www.typescriptlang.org/

PostgreSQL: https://www.postgresql.org/

React: https://reactjs.org/

Transcript

Beyang Liu:

All right, welcome back everyone to another edition of the Sourcegraph Podcast. So, today, I'm going to do a brief intro, a scenario. So, let's say you built your amazing, next-generation web app of the future and you have all the features in place, but you want to enable teams to use it. You now need to go and figure out how permissioning should work in your application, who can see what, who can allow others to see stuff and all the messiness that that involves, but privacy and access control are super important. Especially if you plan to make money. Many of us have been there. I know I certainly have. It's messy, it's a headache. But thankfully, there's a new library that can help with that.

So, today I'm joined by Sam Scott. He's the creator of Oso, a batteries-included open source library for building authorization, straight in your application. It's got a special purpose language for describing your authorization policy, complete with a debugger and repl and a set of APIs to easily bake this into your application. Prior to Oso, Sam was a PhD researcher in cryptography, so he knows what he's doing.

Sam, thanks for joining us today.

Sam Scott:

Thank you very much for having me.

Beyang Liu:

Awesome. So, to kick things off, before you became this expert in all things auth and security related, how did you get into computers in the first place? What was that initial foray for you?

Sam Scott:

Yeah, my illustrious security career started when I was 14 and deleted DOS because I was trying to make space to install more games. I mean, I wasn't that typical security hacker person who grew up coding. I actually was somewhat late to the game, I guess? I was doing an internship when I was going to college and one of the jobs I had was super tedious data entry in Excel. My Monday morning was copy and pasting Excel formulas around and waiting four hours for the VLOOKUP to go through all the rows.

And by nature, I'm super lazy. And I think this is a trait that many programmers have. By nature, I'm super lazy and I was like, "There must be a better way to do this." And I started learning about the world of VBA macros in Excel. Quite a starting point for programming. But yeah, I was able to automate my job away, basically.

Beyang Liu:

Nice.

Sam Scott:

Luckily, they didn't just fire me on the spot. They instead were like, "Hey, this is cool" and nurtured it a little bit, introduced me to some of the actual engineers on the team who took me under their wing from there. That's how it all began.

Beyang Liu:

That's awesome. Okay. So this is an internship that you did during your college years?

Sam Scott:

Yeah, that's right.

Beyang Liu:

Okay. And then one thing led to another... You were math undergrad, right?

Sam Scott:

That's right, yeah.

Beyang Liu:

Okay. So did you come to your senses after graduating and decide to get into computer science or cryptography? Or was this a slow transition?

Sam Scott:

Yeah, for me, it was... I kind of fell into maths. I mean, I enjoyed it and I sort of fell into it, but throughout my undergrad, I was interested in understanding what to do with maths and looking for more applied things to do with it. I'd say most mathematicians on my course were talking to banks and finance places. That was the typical path. It was finance or teaching, in the UK. That's two of the main career paths.

Beyang Liu:

Yeah, yeah.

Sam Scott:

But I randomly learnt about cryptography because my granddad had a book on it and I just started leafing through it and I was like, "Oh, this is super interesting. This is an applied version of maths that can do some real problems," and learned about Enigma and Turing and all the way to modern cryptography, things like RSA. So, that's where it started. It was like, ooh, cryptography is applied maths. And then I started doing cryptography and continuing to want to find more and more applied versions of it.

Beyang Liu:

Yeah. Was your granddad involved in any early cryptographic efforts or was it just a book that he had on a shelf?

Sam Scott:

I think it was just a book he had on his shelf, yeah. I mean, he was himself a mathematician and statistician, but yeah, he was just widely curious and interested in the topic, so I think that's where it was.

Beyang Liu:

Cool. So you got into crypto, which at the time stood for encryption and things like that, not for the crypto currencies.

Sam Scott:

Yes, thank you. Crypto, which I'm now conditioned to saying cryptography, lest someone mistakes me for… Lost that fight.

Beyang Liu:

Yeah. It's over, yeah. Well, we'll see.

But yeah, how was that? So, you went from math into crypto and you ended up doing a PhD in cryptography, right?

Sam Scott:

Yeah, that's right. Yeah.

That was a lot of fun. First, a lot of the cryptography from the maths side of things was very number theoretic, learning about different kinds of abstract math around different structures of numbers or elliptic curves and all this kind of stuff. And it was very fascinating stuff, especially just seeing how some of that could be directly applied to real-life things.

The first paper I published on my PhD was a deeply mathematical topic around solving this bizarre variant of this Diffie-Hellman problem. It's one of these cool cryptographic primitives, used in a lot of things. Very number theoretic, and the paper, it was basically pure mathematics. It was a different approach to solving this algorithm in a faster time. But the implications of it was a real-world attack on a protocol being proposed for EMV credit cards. It was a suggested way that they could basically blind and hide transactions so that you couldn't eavesdrop on transactions and see where they came from. You couldn't say, "This card made those two transactions" if you just listened to the traffic, but there was a small assumption they made that turned into this very interesting number theoretic problem.

I was hooked at that point. That you could be solving these really fun, hard problems and the implications of them are very real.

Beyang Liu:

Yeah. That's awesome. So did you end up doing your thesis on that or something else?

Sam Scott:

My thesis was a mess. My thesis was an absolute mess. Yeah-

Beyang Liu:

I feel like that's not atypical, from what I've heard from my PhD friends.

Sam Scott:

Yeah. Well, I'm sure everyone remembers their thesis as funnily as I do. I mean, my mine was a mess because I moved around a lot and I didn't stay on one topic, because I kept on... It was never enough. It was never applied enough. So, I started out with the math background. I enjoyed that, but I wanted to move out of the math research into some of the more applied stuff. So, that led to me working with, like you said, professors. I was working with some professors out of Cornell Tech. We did a research paper inspired by some password security problem that Facebook had and that took me in a completely different direction. I did a research internship-

Beyang Liu:

Oh, that sounds interesting. Parser security, so defending against... What, essentially denial service attacks where you can make the parser go into infinite loops or something?

Sam Scott:

Passwords. Like username and passwords.

Beyang Liu:

Oh, passwords. Okay, got it, got it, got it.

Sam Scott:

Sorry, it's the accent.

Beyang Liu:

Got it. Okay, cool.

Sam Scott:

Yeah, there was a talk that Facebook gave at this conference called Real World Cryptography, and they basically shared this crazy password hashing onion thing they had where ... they had layers of different code craft because of how cryptography knowledge had progressed. At first, they used MB5 and then MB5 has broken and they used something else, and they had all these layers.

And later, I did a research internship at Mozilla where I was working with one of the editors of the TLS 1.3 specification, did formal analysis of that. And so, I ended up with this mismatch, this random collection of research papers that had very little tying them together. And so I gave it the umbrella term... What was it? The design and analysis of real-world cryptographic protocols, which just meant, "I did things. I looked at things and studied them," and yeah, it was a lot of fun, but it was definitely not a cohesive research topic.

I think it-

Beyang Liu:

It sounds like you were... Oh, sorry, go ahead.

Sam Scott:

I think it was interesting from the survey standpoint, like comparing techniques, but that's not exactly what research is supposed to be about.

Beyang Liu:

Yeah. I mean, it sounds like you were pretty practically minded in terms of how you chose all these different things, and perhaps even at that point in the depths of your PhD, you were already anticipating a jump into industry or more applied stuff.

Sam Scott:

Yeah… The promise of the PhD was that it had a lot of interaction with industry.

I wasn't fully committed to the idea of doing a PhD purely for the research sake and this one had industry tie-in, so that one sort of hit that balance. It was like, okay, I can do a bit of both.

Beyang Liu:

Yeah.

Sam Scott:

Yeah.

Beyang Liu:

Cool. So, did Oso grow out of some of the work that you did in your academic studies?

Sam Scott:

Not in the slightest.

Beyang Liu:

Well, what was the path from that to starting Oso?

Sam Scott:

So, the path was... I mean, I ended up in New York, as anyone who is watching the streamed video of this version can see from my background. This is basically where I live right now.

Beyang Liu:

Nice.

Sam Scott:

I ended up in New York because, as I said, I did some research papers with some people out here in the States and they were keen for me to come out to New York and do a postdoc here. But at that point, I was like, no, I want to go into industry. Academia is not for me. And they said, well, there's a startup program here at Cornell Tech that will allow you to basically explore different topics around different startup ideas, in collaboration with us here, so if you want to investigate some research with us, we can potentially do that as a company idea. Which just sounded absolutely perfect to me. I was like, that's the dream. That's what I want to be doing.

Beyang Liu:

Cool.

Sam Scott:

The program itself, it's called The Runway Program at Cornell Tech. What they do very nicely is they encourage you when you first start out to explore your ideas a bit more, go out and talk to people, understand what problems they're facing. Basically, very gently telling me in particular, "Your ideas are awesome, but you might want to understand what problems the world's facing."

And there was me thinking I was doing very super applied research, but the stuff I'd been researching just wasn't the kinds of things that the real world were actually... Outside of the Googles and the Facebooks of the world, most of the world weren't grappling with these. So that was a rude awakening and it was like, oh, I see, the problems that are out there in the real world are in some ways considered solved by academia, but really aren't.

Beyang Liu:

So, would you say that there are a lot of ideas that are mature in the academic setting that ... there's been no vehicle to make them mainstream? Or is there a complexity in operationalizing some of these that has prevented their adoption?

Sam Scott:

Yeah, it's a bit of both, really. I think the last thing you said really hits on a lot of it, actually. A lot of cryptography, a lot of the really interesting research... If you take a bunch of the research I did assumes that you have a secure way of sharing secrets with each other. And that's the cornerstone of lots of the stuff that everyone uses out there, from passwords or certificates in TLS and encryption, all of them, a lot of them depend on that. And there's plenty of nuances around how you do that. And as it turns out, secrets management is an entire industry in the real world, because it's actually quite fun to deal with. So it's not something that you can take for granted and just say, "Well, assuming we have that, then we're going to go and solve these problems." It's like, well, rewind a bit...

And I think that's what you're referring to when you say the operationalization, it's ... deploying these things and it means some complex secrets management and a bunch of assumptions that you can't typically make, then potentially it's a non-starter.

Beyang Liu:

So, from your perspective, there are just these table-stakes sorts of things that most companies just don't have yet. So before we can get to all the advanced algorithms and cryptographic mechanisms, we need to start with the basics. And one of those basics is just authorization or permissions?

Sam Scott:

Yeah-

Beyang Liu:

Actually, what's the term that you use? Because I hear a lot of things: authorization, AuthZ, permissions, ACLs, practice control...

Sam Scott:

It's a good question. Honestly, we're experimenting with language a lot because what we understand by a word isn't necessarily something that resonates with our audience, with developers. And we do go to great lengths to try and meet developers where they are. So, we try to not use acronyms like RBAC, unless we think that's something that people are specifically looking for because someone said, "Hey, go build an RBAC system" and they're like, "What?"

Beyang Liu:

Yeah.

Sam Scott:

So, yeah, the thing we built is an authorization framework, and what you get from that is a way to build roles and permissions into your application, right? That's like, as an app dev, the product feature you get to ship is roles and permissions and securing access to data. An authorization framework could be the way you achieve that.

Beyang Liu:

Yep. Cool. So, just to take a step back here and context set, when I think of privacy and insecurity from the application layer, there's maybe two main areas that people talk about. One is authentication or AuthN, which is how do you sign in? I think fundamentally that's solving, "Who is this user? Who am I?" And then there is authorization, or AuthZ, sometimes called access controls, sometimes called permissions, which is more about... Given I know the identity of the user, what are they allowed to access? Because in any given application, there's certain data that's sensitive, that's for someone's eyes only and not for someone else's.

And that becomes a whole... It can become messy because there's individual permissions. Those individuals are parts of teams, teams are granted permissions. There might be ad hoc permissions granted back and forth because you want to share data, but only if someone with the proper authority or authorization has the permission to share that data with others. And it often becomes this very tricky problem and it's like, when you're trying to build an application, you want to be focusing on I guess the feature set. And then this whole thing is, I wish it were an afterthought, but actually, it becomes deeply embedded into the logic of your application. And oftentimes, that's tricky.

And you all are trying to solve that, make it more standardized and easier to develop. Because this is also a big source of bugs, I think, right? Someone commits a bug and all of a sudden, someone who shouldn't have access can see sensitive data and that's no good.

Sam Scott:

Yeah, exactly. It can either go... Yeah, it can go that path, where you end up with data breaches, data exposure, or you go the other direction and maybe the controls are super tight, but you end up with a horrible user experience because you end up with these giant matrices of permissions that people need to understand, or opaque error messages where it's like, "You don't have permission to do this, go ask your admin." Like, what?

Yeah. I mean, it has a range. It has a range of implications.

Beyang Liu:

Cool. So, what made you want to tackle this big, hairy problem domain? And what was the backstory? How'd you get into this? How'd you meet your co-founder and what got you started into diving into this problem?

Sam Scott:

Yeah, so I met my co-founder Graham when I was pretty early in that process with Cornell Tech of understanding what problems are out there. And I was having that thought process where it's like ... currently, if you're a developer implementing security, you almost need to have a PhD in security because the tooling's just not there, you need to understand which algorithms you should be using. All those details are exposed that shouldn't be. There's a tooling problem here.

And yeah, I met Graham, who at the time was at MongoDB. And so, he had that perspective from basically the database world, like what if we didn't want every developer to be a database admin in order to deploy an app? And how can we make that stuff easier? So, we instantly had this fun conversation around the problem to be solved there, just making security more accessible for developers. That's how it all started and that's sort of been our north star for the whole time.

Beyang Liu:

Yeah.

Sam Scott:

So originally, we didn't start out with authorization. We originally looked around a little bit in secrets management. We were building an infrastructure security product that did more cryptographic-based things around securing connections between services, with things like encryption and authentication built in.

Beyang Liu:

Got it.

Sam Scott:

We were really going out there, speaking to as many developers as possible, and security teams. And we were hearing a lot of positive things from security teams, but not from developers, who it was for... Some of the infrastructure security staff would rather just not be dealing with it at all. But we did hear from those teams. They'd say, "Yeah, we don't really handle the TLS between services, things like that. But we did just spend 9–12 months building this roll system," or, "We just spent all this time building an authorization service. Does your product handle that?" And at the time, we were like, "Nah, we're doing the infrastructure thing."

And honestly, it didn't feel great. We were building this product that wasn't really resonating with developers, it was more resonating with security, and it was getting away from that original goal. So, almost two years ago, we decided to pivot towards the application authorization side of things, go back to those developers we'd spoken to, and understand that use case a bit more.

Beyang Liu:

Yeah.

Sam Scott:

And that just felt like a huge load had been lifted off us. It was getting back to our... like a huge load of being lifted off fast. It was like getting back to our base.

Beyang Liu:

Yeah. That's awesome. What sort of pain points came up frequently when you spoke to developers and they shared their access control experiences?

Sam Scott:

Yeah. It was really interesting, because it wasn't ... We had such a range. As I said, there are some people who just said, "We just spent," whatever, "nine, 12 months building this system. Where were you two years ago? We could have just skipped all that work." That's what you love to hear as a founder.

On the other hand, we did hear a lot of people who just were like, "I could never even conceive of ... Authorization is a core part of my business logic. I can't give that to you. I can't move that to something else. That doesn't make sense to me."

Or it's, "How do you solve this problem when we fetch all of the" ... This was a particularly insightful company who brought this one up. It was like, "We have this problem where we need to fill the data coming back from the database, and only return the ones that a authorized user can see. How could your product possibly solve that?" Because we could steal this work.

Beyang Liu:

Yeah.

Sam Scott:

Yeah.

Beyang Liu:

Because, from their perspective, it's like, "I wrote all this code," and it's really probably indistinguishable in the codebase from the "regular" logic. It's probably some conditional that checks the user ID in the code. How do you rip that off into a separate ...

Sam Scott:

Yeah, exactly. It's probably something every other company would do. When you start fetching records from the database, you filter them by the user's organization ID, or something. It's this kind of authorization logic. If you go multi-tenant, then how do you do that?

I think what we were really hearing then, which we didn't know at the time, was ... I think that's a lot of why it's been hard to solve this problem in the past. How do you balance those two tensions? There's lots of work that people often do, but they often reinvent it, but it's deeply embedded in the application. How can you solve that?

Beyang Liu:

Yeah. It's also scary, though, to have that deeply embedded in the application, because the application code changes, often frequently. What's to say that some developer who's trying to ship this other thing quickly inadvertently removes that conditional that is the hinge upon which the entire enforcement of the permissions model relies?

Sam Scott:

That's a really interesting one, because, at the same time, if you try and pull it out of the application entirely, then you might end up having something that is fundamentally changing your app logic that is now being decoupled from it. You can potentially deploy changes that just breaks your entire app, because it's ... There's a really tough balance to get there. In some ways I think I'd rather have changes to my authorization logic go through my regular CI process, because it is just part of my app and I want it to be tested in that way.

Beyang Liu:

What is your principled way of thinking about authorization? You've written a lot of guides on how to think about AuthZ. Oso has published a lot of useful guides. You've broken it down into different parts, enforcement, decision, and things like that. Is there a 10-minute primer that you can give me that lays out the core things I should be thinking about with respect to AuthZ as an application developer?

Sam Scott:

Yeah. Absolutely. Let's talk this through. Let's do this using an example, and I'll walk through a typical request to my web app and what's going to happen. We use GitHub a lot, as an example. It's got some very rich data structures, and everyone's familiar with them.

Think about the process that GitHub might go through when you go and click, I don't know, merge on a pull request, or something. The request gets fired off to go merge that pull request. It maybe goes through various different API layers, and eventually it maybe reaches the ... You have a choice, like, "Do I want to try and do authorization over this request object?" This HTTP request comes in. I could probably inspect it and see, "This is a merged pull request to," such and such a, "the Acme anvil repository. I can see it's this user from the token."

You could try and make an authorization decision right there over that request, but probably what you're going to end up doing is fetching authorization information from a database, like the author of the application data. We'll get back to that one in a sec, but ...

You're deciding where you do that little piece of logic, saying, "Should this request go through or not?" That's enforcement. You can choose different layers inside your app of where to do enforcement. What I was describing was maybe at the front door, the entry point, at the API level. I could maybe inspect that request and say, "Is the request authorized or not?"

More typically what you see is that that logic is handled more inside the application code, like in the web controller, that type of thing. Inside whatever is your Rails app or something, you've got your controller method that's to merge your PR. That's going to check that logic. It's going to say, "Okay. I've got this request to merge this PR. I've fetched the current user," probably in some middleware, "and now I want to do that enforcement of, should I let this go through or not?"

Basically, that point, you switch over to the authorization decision. Basically that's the point where you decide, "Should this user be allowed to perform this action on that resource? Should this user be allowed to merge a pull request in this repository?" We call that the decision.

Beyang Liu:

Got it.

Sam Scott:

Basically, within the decision, there are two sub-pieces that are really important. One is the abstract logic, and the abstract logic means the structures, the models you have in place to make those kinds of decisions. More concretely, we're talking about things like roles.

A lot of logic inside GitHub is modeled around not what a user can do, but what a user with a role can do. It's like, "I see. Sam as a," whatever it is, "member of the Acme organization, and the anvil repository belongs to that one, has certain privileges." That, right there, is the abstract logic piece that says, "Members can merge PRs."

Deeply coupled with that is the authorization data. If the logic is the abstract piece, the data is the concrete piece that filtered in. It's the bit that says, "Yes, Sam is a member of this org." It says, "This repository belongs to that org." It says, "This pull request is inside that repository." All of those are pieces of data, and they typically live in your application, in your database.

You basically need the two. You have the code, the core logic, plus the data. You put them together, and you can make a decision. You can say, "Yes, Sam is allowed to merge this PR."

Beyang Liu:

Got it.

Sam Scott:

That's your typical authorization flow as it goes through those pieces. The request gets to the enforcement, enforcement needs to ask that question, get a decision back.

Beyang Liu:

Can I ask you a question about the enforcement aspect of it?

Sam Scott:

Sure.

Beyang Liu:

I remember having this debate with another engineer on our team once upon a time about where the proper place was to enforce the Auth policy. The two options were the API layer, as you mentioned in your example, the argument being the API boundary is the outer boundary of the application. This is the point which you should be checking for permissions, because anything that's leaving this boundary is going to some consumer on the outside. This is the point where we need to guarantee permissions.

The other side of the argument was, "No, it should be actually as close to the underlying data as possible," because the data in the actual database, all that is sensitive. You don't want to have this thing where you combine bits and pieces of data at the API layer or in some middle layer, and then you miss the check at the data layer. Then the API author doesn't realize that there's actually private, sensitive data jammed in somewhere in this API response, because it's gone through so many transformations on its way to the end user.

Then the counterargument to that was, "What about something like search?" Which is directly relevant to Sourcegraph. Where it's like, if you check the union of all possible matches before you actually do the search, then it's intractable. Because you're not going to check every single possible line of code for its permissions, you're going to run the search first, look at the results that you get, and then filter afterwards. Much more efficient to do that.

There's a whole conversation around proper place to enforce the authorization model. Do you have a principled way to think about this? Is there a mental framework that you've just-

Sam Scott:

Yeah.

Beyang Liu:

I know it's an impossible question to answer, but-

Sam Scott:

We've tried.

Beyang Liu:

What would be your approach?

Sam Scott:

We've tried. Yeah. Welcome to why authorization is hard/fun. We wrote an entire 5,000-word guide on this.

All right. There are, I think you mentioned, two places you can do enforcement. I think there's really four.

Beyang Liu:

Oh, wow. Okay.

Sam Scott:

One of them's kind of a trick question.

One place you can do enforcement is in the user interface itself. But the caveat there is that can't be the only place you do it, because someone can easily bypass your frontend code and just make a request themself, so it might be an additional one you want to do. That's the classic, "Don't display the delete button if the user can't delete the thing." That's kind of like informed enforcement. That one's nice. It's kind of separate, but it's nice. Yeah.

Then you have, you say, the API layer we call the request layer. You have inside the application codes, inside a controller method, inside the core business logic. Yeah. Then you have, at the data access layer, and ... Yeah. It has the trade-offs that you mentioned, like, doing something as an API middleware can sound so good, because you can just say, "I'm going to do it once. It's going to apply to every request, and I'm never going to forget it."

But what ends up happening is, to be able to make that authorization decision, you need to end up basically duplicating a bunch of what the application logic itself does, to understand to turn that request into something meaningful so you know the right thing to authorize. That ends up being pretty painful and duplicative.

It hits on this topic that comes up a lot, which is that the thing you're really striving with authorization logic is to have this clean separation between the application code and the authorization logic. It's very easy for those lines to blur in either direction.

This one would be an example of actually your app code spilling into your authorization logic, where you're now reimplementing your request routing mechanism that can pass HTTP requests into business logic. What those things mean, and what those things need to do, and so on. Typically, we just say, request layer, you should only use it for very coarse checks that you really can do at that layer. Which can be things like, "Is the user logged in?" Maybe it's a request coming with an API key, and the API key has a list of scopes of what it can do. When you get into that granularity, you can just do this thing where it's like, "This API key only has the read scope, but it's trying to do a POST request, so I'm going to reject it." It's like, "That checks out."

But, yeah, really you want to do your ... I think the best place is closest to the data, is one way of putting it. We say it's where you can ask the most specific version of the question, like where you have all the relevant context of what the user's trying to do and the action you're actually trying to authorize or enforce, because authorization is messy.

I had a really interesting use case the other day where it was ... I'll keep it pretty generic, but it was an app that needs to access a piece of personal information, and it was allowed to on one page, but not on a different page. Because you might think that there's a clean abstract authorization model, but, really, everything has business requirements. This one was like, "If they're in this page flow, then, yes, they can see that piece of personal information, but in this page flow they can't." They're like, "I know it's terrible, but that's how the app works. That's the business requirements." That context was necessary. That's a pretty extreme example, but you get similar versions of that.

Yeah. You want the authorization in the most specific place you can. One thing you can often do is apply broad, generic checks at the data-access layer. Like, "Make sure the user's allowed to read this piece of data," or, "Read any piece of data that comes back from the database. The user should be allowed to read it." That can be a really good filter that you apply to everything.

It might be the case that afterwards you need to go and check something else, like, "In this case, they're actually trying to update this field," or something, and then, "Go and check the user can update that field," but it actually makes a really nice balance between having that authorizations applied to everything by default, without you needing to get too clever around how you tell the database layer what things to authorize. That's where it gets tricky.

Beyang Liu:

Yeah. Makes sense. Do you see people combining enforcement, different layers, almost as a double check? Like, "Yeah, we're checking this at the data layer, but might as well apply this other check at the API layer, just in case something-"

Sam Scott:

Yeah. Absolutely. Defense in depth. It's all about that. That's great. As long as the system you have is convenient enough for doing that, and you're not going to end up hating yourself for doing it, if the tooling is good enough, then absolutely. Why not?

Because what it does mean is, yeah, you do miss an authorization and enforcement check, and your test caught it, or something. But maybe you still have that request-level check, so at least the user needs to be logged in, or something. It's not just completely open to anybody. Defense in depth can reduce that blast radius.

Beyang Liu:

How does Oso help with the enforcement and decision, these two big categories? Is there one or the other that it's more interesting for? Would you say it's both? What would be the first cool thing to show off?

Sam Scott:

They're both so cool. I'm not sure which is best. I'll leave it to you and the viewers/listeners to decide which is coolest, but ...

On the enforcement side, we have a set of APIs that basically help you do authorization and enforcement across any of these layers. If you want to apply your authorization logic over your database queries, or if you want to expose stuff to the UI, we have APIs to help with all of that.

Beyang Liu:

Cool.

Sam Scott:

That's fun. We can see that in a demo, how that turns out.

Beyang Liu:

Yeah.

Sam Scott:

I think the logic side is really interesting, because we basically built a language to help with writing and expressing authorization logic in a way which we hope removes a lot of the difficulties and allows you to focus on the core, "How do I want my app to behave? How is my app structured? How should it work?" ... Instead of the tedious, "Making sure I got my logic in all the right places," and things like that. That stuff is pretty novel and new as well. The nice thing is, the two go hand in hand. We have all these different players in places where you can do enforcement, and they all just use that one single piece of logic, which is nice.

Beyang Liu:

When you're explaining Oso or showing off Oso to new users, do you typically start with the decision side or the enforcement side?

Sam Scott:

That's a good question. It depends on what problem people are trying to solve, honestly. I will say, a lot of people ... Yeah. When you put it that way, a lot of what we do hear from people is, "I'm not sure how to even think about my authorization structure right now. I'm not sure what model I should be using. Can you tell me?"

Beyang Liu:

Yeah. Why don't we start with the decision side, then? Because I think that's where the Auth model's actually defined. Then maybe that motivates, "Where is this enforced?" Or, "How do I actually enforce this now?"

Sam Scott:

Yeah. The enforcement is the bit that makes it concrete. Like, "Now here's how it's actually going to look in your app." It makes it real. Yeah. The logic piece is solving that hard modeling challenge, and the enforcement makes it real.

Beyang Liu:

Cool. Does this play into ... You have a mini demo, right?

Sam Scott:

I do. Yes.

Beyang Liu:

Okay. Cool. Then, for those listening to this, there's video on YouTube, but for those who prefer the audio-only experience, I will do my best to narrate what is happening on screen.

Sam Scott:

One place we could also start is ... It can often be fun actually just to hear from you. What's an application model you'd be interested in thinking through? We could talk through a use case live, and then I can go and show the more complete version of the demo. How about that?

Beyang Liu:

Yeah. That sounds good.

Sam Scott:

All right.

Beyang Liu:

Can we use Sourcegraph as a motivator?

Sam Scott:

That's right. Yeah.

Beyang Liu:

Cool. Yeah. Do you just want me to describe ... I'll caveat this by saying my understanding of the AuthZ model, because there's people closer to that code than I am right now.

Sam Scott:

Yeah. We can just talk in the general things. Okay. A really nice starting point is, what's the core resource that you're protecting? What's a really good example of a typical representative piece of data that you're trying to protect in Sourcegraph?

Beyang Liu:

For us, it's all about the code. Which code are you allowed to see? Private code. That's typically permission by repository. Some people are allowed to see a particular repository, some people aren't. Some repositories are public, some are private. Some are open to anyone inside the company, but they're not open to completely unauthenticated users. You have to be a member of the company. There's a notion of teams and organizations, too. A team can be granted access to the code.

For us it gets a little bit complex, because some of this we try to sync over from code host permissions models, but, some of our customers, they either don't use one of the standard code hosts, or they do, but they have their own Auth permissions malarkey in the mix, defined in LDAP something or other, or-

Sam Scott:

Lovely. So this could get a little, it's going to be very overlapping because the demo I have is also a GitHub clone. So we're going to have the same. We're going to have identical concepts in a second, but let's run with this one for a second. I think this will work. So right now, I'm inside. Whatever, I'm inside my editor. I am writing. You can see I'm writing in the bottom right, it says Polar. The policy language that we developed at Oso.

It's a logic-based programming language. That's kind of a fun, separate topic that most people don't read.

Beyang Liu:

It's like Prolog?

Sam Scott:

It is heavily based on Prolog, but with features that we built in particularly to be amenable to authorization.

Beyang Liu:

Cool.

Sam Scott:

So, kind of the starting point, with Oso, writing policies is kind of describing your resources. And so you just mentioned repositories. And so what I'll start out with is what we call a resource block for repository. And basically these blocks, they're just helping us define the kind of the shape of my authorization logic. A lot of it is very resource orientated.

Beyang Liu:

So you just type in resource space, capital repository, then open brackets.

Sam Scott:

Exactly.

Beyang Liu:

Yeah. Open curly brackets, yep.

Sam Scott:

Within this resource block, basically what it also wants me to do is define, sort of declare the different things that can happen on a repository or that exists on a repository. So I'm going to add a few...

Beyang Liu:

There's like read-writes...

Sam Scott:

Exactly. Sorry, I'm going to write the list of permissions that will exist on their repository. So what I will say, read and write.

Beyang Liu:

These are all actions that can be performed on this resource?

Sam Scott:

Exactly. These are all things that we would want to get grant and access to, can someone read a depository, can they write a depository. So that's kind of one thing. Typically people will also express roles. If you're doing role-based access control. We can leave that one blank for now. We'll come back to that. But if we had roles we'd...

Beyang Liu:

What about something like an admin-level access where I can grant other people read or write permissions? Is that something that you would put in permissions? Or is that, so you just added admin roles, but the ability to grant read and write, is that another permission or is that going to be described elsewhere in the model?

Sam Scott:

Yeah, okay so you're touching onto a kind of an interesting philosophical or modeling question here. So generally, I would say that the best practice would be to try not to mix and match authorization models here too much. So if you want to go with roles, which I think a lot of people should. Very clean approach. Stick with roles. So rather than saying an admin can grant someone read and write permissions. I might say, admin is allowed to assign someone a role and we're going to stick with roles for who can do what.

Beyang Liu:

Got it.

Sam Scott:

Now, I guess I might otherwise have a... I'm not sure I'd construe it as an admin, but let's say instead that we had maybe an ownership concept, like a document management system, you're the owner of a document and you can just grant people direct access to something that you just grant them directly read and write access. You might do that through a permission. It gets blurry.

Beyang Liu:

I see.

Sam Scott:

Okay, let's do an admin a member, and indeed we might complete what we're talking about. Let's add to permissions that there is also a permission to assign role.

Beyang Liu:

Okay. So I've got three permissions: read, write, assigned role, and then two roles, admin and members. All within the repository.

Sam Scott:

All within our repository resource. Now we might come back and change this later. It's kind of, this is the point of the policy language here is that we'll make that nice and easy. So the third thing you declare inside this resource block would be the relations. And this is an incredibly powerful concept to have inside your authorization model. So again, it's another thing we put inside the block. Instead of in a list, this one's going to look more like a dictionary.

And basically what the relations are, you are going to have, the key of this dictionary is going to be the sort of, relation name. And the value will be another resource. So we've only got repository right now as a resource, but you mentioned organizations earlier.

Beyang Liu:

Yes.

Sam Scott:

So I might, for example, say that a repository has a parent relation and the parent is a type of organization. And so basically what I'm doing here is I'm declaring the structure of my app data as well. So I'm saying to your repositories have a parent organization and by declaring that I'm going to be able to use it in my logic later.

Beyang Liu:

Yep.

Sam Scott:

Okay, cool. So that will declare the main things. Now I can start doing inside this resource block is, I can start assigning permissions to roles and things. We've already said earlier that admins can assign roles. So the way I'd write that, I just write... It's still inside that same block. I can just write, "Assign role if admin."

And basically this syntax here is kind of shorthand syntax for, Polar roles and Polar logic and basically says, user has a permission to assign a role for a repository if the user has the admin role for that repository. And we sort of know this because that was the information we declared earlier and just like that I have now granted permission to an admin and we can kind of go through and do some of that, right? We can say, maybe read if you're a member. That sounds about right. You could write.

Beyang Liu:

So you're just listing out these conditionals, which my mental model is you'll just get executed in order to check if, I guess later we'll inject a user into this with a particular role. And if any of these returns true, we return true. Otherwise if it falls to the end of this without triggering in these conditions, it's false.

Sam Scott:

Exactly. That's a great point as well. The model here by default, everything is just deny. So when I just start out with Oso, or just...

Beyang Liu:

Default deny.

Sam Scott:

You can reject everything.

Beyang Liu:

Cool.

Sam Scott:

And that's, again, that's kind of, I'd say it's considered a best practice insides for authorization permissions is you always want to be additive...

Beyang Liu:

That makes sense.

Sam Scott:

... As soon as you start going into negatives, you can do it, but it will make your life harder. And you just sort of reserve that until the last possible moment. Yes, you're right. So it's going to go through, it's going to check each of these, these kind of little rules and if none of them are true, then the user can't do a thing.

Cool. Okay. So that's my resource block. And basically the way this is going to actually evaluate through. Sort of by convention, we have this entry point to a policy, which is an allow rule. And basically, this takes the format of... This is the same structure of an enforcement thing. So you say, a user is allowed to perform an action on a resource if and then some conditions are true.

So what we're looking at now, this is like the full expanded version of Polar rule syntax, where we're getting into the logic programming. Sort of looks a little bit like a method, except there's kind of this conditional syntax thing.

Beyang Liu:

Yeah, it's interesting.

Sam Scott:

Basically what we need to check is that the user is allowed to do their thing, if the user has permission to do a thing and the permissions are defined by that resource block we built. So when I was talking through it, I said, a user has permission to assign a role. If the user has the admin role on the repository. So now I've kind of hooked everything up. That's my authorization model.

Beyang Liu:

Where's permission defined though? It looks like you're invoking... Are you referencing something called, has permission there?

Sam Scott:

When I said these...

Beyang Liu:

Like a built-in...

Sam Scott:

That's basically referencing these. The rules that we expressed inside this resource block. So the re-definement is actually kind of described, is expanding to a... The full version of that is, has permission, takes user and it says they can read repository. Has role, and so on. So this is shorthand syntax for that. So that's what's being referenced.

Beyang Liu:

Okay.

Sam Scott:

We debated removing this and just making this the default, but we kind of like the explicitness.

Beyang Liu:

Wait, so sorry. What is shorthand for what? Is it the list of conditions? The list of conditionals is shorthand for the... Otherwise you would've defined has permission inside the resource block?

Sam Scott:

Yeah, this would be the full version of it.

Beyang Liu:

Oh got it.

Sam Scott:

So you have to write has user to repository if has role, user member repository.

Beyang Liu:

But that's, would you put that inside the resource block?

Sam Scott:

The resource block here, it's just for writing. This is kind of like syntax trigger in here to basically make it easier to write...

Beyang Liu:

I see.

Sam Scott:

...this complex logic.

Beyang Liu:

Got it. That makes a bunch of sense.

Sam Scott:

Sorry. This is actually kind of a nice segue because some of the things you mentioned earlier was some repositories that are public or private, and so on. So kind of the nice thing about this system of this kind of rule logic, because it's very easy to bring in, to extend it, customize it, add your own piece of logic. So for example, I might say that a user can read repository if the repository is public. So instead of has role, I'm just going to write repository.public. And in this case I can actually edit user.

Beyang Liu:

Now that implies the existence of an attribute called public on repository.

Sam Scott:

Exactly. That implies that, exactly.

Beyang Liu:

Do you define that in the resource block then, in Polar? Or was that just something, is it like JavaScript where you just reference things that may or may not exist as attributes.

Sam Scott:

Now we're kind of getting into the application data piece of things. So remember we said, decisions is logic and data. I think the piece you picked up on is, we've been writing logic so far, where's the data coming from? And basically with Oso and the way we built the library is that you could... You would be expressing your logic over your application data. So repository.public—that will be coming from your application. I mean, repository will be the concrete instance of an object or coming in from the application. So we're reading it off of that. So when we check in that permission, we will read it off of the repository.

Beyang Liu:

And I assume that if any of these are undefined, then it will just fail.

Sam Scott:

Exactly. You'll get an error, it'll say.

Beyang Liu:

It won't do the stupid JavaScript thing where it treats undefined as falsey. And then, depending on how you define your logic here. If your application accidentally leaves that field off. I assume that all that works in the way you expect it to.

Sam Scott:

Well, that's a really interesting question. This is one of the things we have to deal with is because the logic here is separate from the host language, JavaScript, Go, Python, whatever it is, we just decide what's the right way to do in each language.

Beyang Liu:

Okay.

Sam Scott:

Yeah, we actually decided to be stricter here in JavaScript land than JavaScript itself, where we recently added the check that if the field doesn't exist on the object, we will throw an error. Even though JavaScript will happily return undefined.

Beyang Liu:

Thank you. I think that was the right, it sounds like the right call.

Sam Scott:

Yeah.

Beyang Liu:

Err on the side of being a little conservative.

Sam Scott:

We've been discussing this one a lot. It's a really fascinating question to get that boundary right. I think there's more we can do here to be, go a little bit more on the strict side actually. And there's an interesting balance between ease of use here and not requiring you to do a bunch of work, but also get that sort of correctness and straightness. We've got some plans on how we can have that even clearer and sort of have that interface that's stricter as well.

Beyang Liu:

Cool.

Sam Scott:

All right. So there we go. We have your authorization model. What do you think?

Beyang Liu:

That was easy.

Sam Scott:

I'm glad you think so.

Beyang Liu:

This is like 20 lines of code.

Sam Scott:

Okay, let's...

Beyang Liu:

Yeah, not bad at all.

Sam Scott:

I think what we've done so far there, it's pretty clean, but it's not. I wouldn't say this is something that is really... It's not doing that much yet. Which is based on the role you have in repository...

Beyang Liu:

It's a very simple...

Sam Scott:

Your assigned role.

Beyang Liu:

Yeah.

Sam Scott:

I think where this gets really, can get very powerful is if we come back to this relations thing. So I kind of hand waved around it, parent organization. We'll come back to it. So let's do it now. So I'm going to add another resource. My organization resource, much like I did with the repository, the same syntax. And I mean, let's say, maybe this is, we admit design. We're going through, we're talking through how we want to make our logic work and you help me point it out.

That actually we don't want to have to have admin member roles on every repository. Actually, that's an organization-level concern. And so what I'm going to do, I'm actually going to move those roles up into my organization block instead.

So I'm going to move them out of repository into organization. So now our roles define the organization instead. But down here in my repository resource block, I said, read if member, which meant you can read a repository if you're a member of the repository. But that's not a thing anymore. Now it's a member on the organization. And so we have this additional piece in the shorthand syntax. There are already only two things you can write. This read if member and this second one, which is, you can say read if member on parent. And the parent there again, referencing this relation to an organization. And so what I've now written here is instead of just saying, you're a read if you're a member of the repository, it says read if you're a member on the parent organization.

Beyang Liu:

Got it. Can you compose? So my brain immediately goes to a relation is like an edge from...

Sam Scott:

Yep.

Beyang Liu:

... One node to the other repository to organization. Now what if you had some other thing called like super organization and that had its own roles. Could you do like read if member on parent on, I guess, parent?

Sam Scott:

We decided to not allow that and there's no technical reason. It's more of a not handing out too many...

Beyang Liu:

Describing best practices.

Sam Scott:

Yeah.

Beyang Liu:

Fair enough.

Sam Scott:

But we will see a model of that. I mean, we're getting very close to GitHub's organize model here, but so suppose I've got a different child, I've got like an issue and another issue resource. And we're going to have, same if for the parent of an issue as a repository. Then indeed what I might want to say is something like you can read a repository if let's say.. I'm guessing I'll find my permissions down here as well... You can read a depository if you have the recommission on the parent. And now we are sort of composing because you can read the issue if you can read the depository. You can read the repository if you're a member of the organization. We are kind of doing arbitrary things...

Beyang Liu:

That makes sense.

Sam Scott:

To create things but I think keeping them one hop at a time, so far, we feel this is a slightly better balance of...

Beyang Liu:

Yeah. So what you're essentially prescribing is the authorization logic for a given resource should be a little bit agnostic of roles beyond one level out.

Sam Scott:

Yeah. Pretty much. I couldn't come up with a use case where... For example, we don't really have a model in our... I couldn't think of a use case where you wanted to say what someone could do to a specific issue where you wanted to skip what they could do on the repository and go straight to the organization. It didn't quite make sense to me. Even if you have that can do anything, then that means they're a super admin on a repository. If you'd like to just do that.

Beyang Liu:

If you think about how your human brain thinks about it, it's that issue belongs to that repository. And if I'm able to do something on that repository, I should be able to do the "similar" action or the same action on the issue. You're not thinking of the issue of belonging to the organization because it's kind of fully contained within.

Sam Scott:

Exactly. And it just, it reduces the number of paths of trying to figure out, trace through in your head.

Beyang Liu:

Yeah.

Sam Scott:

Cool. I think that's a pretty reasonable summary of all the things that are going on here.

Beyang Liu:

I mean, this is a non-trivial auth model now. You got repositories and issues an organizations and...

Sam Scott:

A hierarchy of resources.

Beyang Liu:

You've brought in very little code. It's like 26 lines of code.

Sam Scott:

What I love about this is my favorite piece of this is, we just kind of had a conversation, right? And that's how I try and I want to think of it. I want people to have a conversation with Oso, where it's like, I'm just going to tell you what I have in my hands. I got these relations, I got these resources. I'm going to tell you what I have and lay that out. And then I can just start talking through, all right. What do you want to work out? Okay. Maybe we weren't happy with read if read on parent. That doesn't feel granular enough. I don't know. There's too many things, I don't want to group them together. Now I'm going to bring in repository roles.

I'm going to put admin under repository on a repository. And I'm going to say that, you're a member of repository if you're a member of the organization. That's just implied things. You can just shape it, however you want. And all of these changes are just, you just focus on the logic. We haven't really spoken about the way this integration with application data, but we can look at it. We can look at a live demo, and play around with that and see it changing.

Beyang Liu:

Yeah. I would love to see how enforcement looks because I'm liking this so far. I like the cleanness of this and how it's separate from... Because I'm trying to think how would I introduce the authorization logic at Sourcegraph to a new engineer onboarding right now. It'd probably be a lot messier than this. It'd probably be like, okay, this is the function that gets invoked in every low-level data handler. That's kind of, enforcement, but it also involves a bit of the policy checking the decision, because in that function, there's a bunch of conditional statements, if statements. That reference functions that check various parts of the auth model.

Sam Scott:

So yeah, let's check it out. So hopefully we've just been doing all this in the domain model of GitHub. So there's going to be kind of, there's a context-switching here to show a demo app. So basically we have this demo app that we called GitClub. So, a GitHub clone. It's available on GitHub. Wow, that gets confusing.

If you go to gitclub.dev, gitclub.dev will take you to the repo that has this, that has this code in it. This is all public stuff. So we have this app that basically shows you what this looks like. Kind of in a real one. We have different backends to show in different languages. I'm going to stick with the express one. I want repo control.

Let me zoom out a little bit. Okay. Let's look at this. I'm going to just move everything else up the screen to focus. So let's look at this control methods.

Beyang Liu:

So this Typescript code you've shown off before.

Sam Scott:

Yeah this is our express TypeORM TypeScript example up.

Beyang Liu:

Okay. And you're taking in what looks to be like an HTTP request or some representation of that.

Sam Scott:

Yeah, this is an express request object. This is our controller method to fetch a single repository.

Beyang Liu:

Got it.

Sam Scott:

We're going to go and fetch that repository from the database using TypeORM. And basically just call this Oso to authorize method. It takes in the user from the request objects, authorize if the user can read the repository and that's it.

Read the repository and that's it. That's like the one method we need. If this fails, which is just going to return, you know, throw an error. It can be handled by error handlers, things like that. Yeah. That's the enforcement. That's it. Same API everywhere, basically. And so if I scroll down to my like-

Beyang Liu:

Wait, wait, wait. Go back a couple questions. Okay. So, okay. Request Oso to authorize. Okay. And then you're just passing it to the user, and then you're passing the-

Sam Scott:

It's the screen.

Beyang Liu:

The information that you want to.

Sam Scott:

Yeah. So the action the user's trying to do.

Beyang Liu:

Okay. And then, the repo.

Sam Scott:

The repository itself.

Beyang Liu:

Okay, that's cool. And I assume that it like throws an error if it's a no.

Sam Scott:

Yeah. So there's a few best practices we've encoded in here as well.

Beyang Liu:

Because you want to avoid conditional errors, I'm guessing. Like if a return a Boolean, and then you ignore it, you check the conditionals?

Sam Scott:

Yeah. I mean, that one hand is just a bit tedious to write if authorized everywhere.

Beyang Liu:

Yes.

Sam Scott:

If there's another possibility we cover here, which is often if the users are not allowed to read something, you actually often want to return a 404, a not found error to them, because sometimes just reviewing the existence of the thing is bad. Right?

Beyang Liu:

Yes.

Sam Scott:

I could go to the Oso org, I don't know, top-secret projects, and maybe that project code name is like, I don't know. I don't know, a Sourcegraph competitor or something. Oso/Sourcegraph competitor. I don't want you to be able to like try and hit that URL and tell you you can't read this. I want it to pretend it doesn't exist. It's private. So, we bring this into the interface as well.

Beyang Liu:

Oh, cool.

Sam Scott:

Because this is going to be a repository that's really easy to forget. Right? Like, let's go and look at our delete endpoint to delete a repository. So here we're going to check and you delete the repo, exactly the same method as before.

Beyang Liu:

Yeah.

Sam Scott:

So fine. Like maybe you try and delete Oso/Sourcegraph competitor, and it'll just tell you, like denied. You can't do that. So, at least I didn't let you delete it.

Beyang Liu:

Yeah.

Sam Scott:

But in telling you can't do it, it tells you that it might exist. So, actually what you'd rather do here is if you're not even allowed to read this, I should just 404. I should just like hide it from you entirely. So, this is what authorize will do. It'll first check, are you allowed to read the repo? If you can't, it's going to raise a 404 error, if you can, so you actually are a member of Oso, but maybe you don't have the right permissions, you don't admin, you'll get forbidden.

Beyang Liu:

Yep. Now as a question here, I wouldn't expect you to do this, because this is maybe like overly paranoid, but like one of the considerations here is if you don't want to leak the existence of certain things, like timing, it can leak that information too, right? Like if it's an auth check that fails, then may return very quickly. But then if it actually doesn't exist, it goes through to the backend and maybe, there's more work that needs to be done there. So, the request latency is higher. Do you have any facility for like trying to mask that difference in latency as well?

Sam Scott:

Yeah, well actually yeah. Yes. In short, yes.

Beyang Liu:

You do? Oh, wow. That is surprising.

Sam Scott:

So, not through the approach that I've shown here, but if I go up to... We'll come back to that one in like-

Beyang Liu:

You don't have to show this off, just the fact that it exists.

Sam Scott:

Very shortly. Because I want to show you. We'll take a tiny detail through a different enforcement phase. So, okay. Along with fetching, leading a single repository, we have our index endpoint. Right? So, get me all of the repositories. And in this case, for context, this is like a sub path on an organization. So, we're doing like a little bit of extra logic here, but basically our user one says what are all the users there? On an organization page list, all the repositories. Now that list of repositories, like in some cases it might just be if you can see the org page, then you can see the repositories, but it might be that the index page itself is public, but specific repositories are not public.

And so, we have this additional enforcement interface here, authorized query. Which is basically, you can see here, instead of taking in a concrete repository it takes in the... This is like the class name, basically, the model, and it outputs a repository filter. So, this is something I can append to my data access, to my database query, to filter down repositories by only those I can see. And it's going to take all of that lovely authorization logic we wrote earlier and basically, compile it down into, well in this case, TypeORM filter statements.

Beyang Liu:

Interesting. Okay. So you get the org, and then you authorize and list repos just as like a pre-check, and then you invoke this authorized query method, which is on the Oso object, oh, and that returns the filter object, which you can then use-

Sam Scott:

That can depend on my actual query.

Beyang Liu:

... The filter. But doesn't this make the enforcement a little bit, maybe less safe? Because if I'm just scanning this code, I see this await, request authorized query line, but then what if the application developer forgets to use the filter that's returned by that?

Sam Scott:

So there's a chance, yeah.

Beyang Liu:

I guess. Yeah. You can only do so much.

Sam Scott:

They could also make the terrible decision of not using Oso in the first place and they even, yeah. Yeah. It's a great question.

Beyang Liu:

This is a question I ask sometimes, do you have any sort of like static check library too, that just checks that the code invokes Oso in the proper places? Because that is something that I've considered for Sourcegraph, just out of like abundance of caution.

Sam Scott:

Yeah. There's more we want to do here. This isn't something we've exposed yet, but the sort of the idea of... One of the things we do want to add to the product is, basically something that can check whether authorization took place in a request scope, in a request band. So, you kind of know that at least somewhere authorization was applied. Yeah.

Beyang Liu:

Oh, that'd be cool. Yeah.

Sam Scott:

We don't have that right now, but yeah. More to come.

Beyang Liu:

Makes sense.

Sam Scott:

Cool. Yeah. So this is really nice, because the authorization largely, as we saw, can get quite complex, but the enforcement will stay the same even over these index endpoints. And so to come back to your other question around like hiding whether the timing attack potential between seeing the resource and authorizing the resource, if you apply this kind of path in everywhere, so if you use that like data-access-layer path in everywhere, then anytime you fetch anything from the database, it's going to have that authorization applied. And I mentioned this earlier, right? Like if you just applied read-level permissions across everything, then the app literally can't differentiate if the thing exists in the database or not. Every time it fetches it's just pre-filtered by authorization.

Beyang Liu:

Which is beautiful. It's like exactly what you want.

Sam Scott:

Yeah. A lot of people talk about doing this fully in the database, like PostgreSQL, like role-level security and stuff like that. The challenge of that is you end up duplicating a lot of your application logic in the database, but it's got a similar approach to that.

Beyang Liu:

Yeah.

Sam Scott:

All right. So, let's see what this looks like in a real app. I feel like we've been staring at code long enough.

Beyang Liu:

All right. Let's do it.

Sam Scott:

So, here is my here's my beautiful React app. Super modern, responsive. So, yeah.

Beyang Liu:

Gorgeous.

Sam Scott:

You can see up here I am... Let me log out first. I'll probably get some horrible errors from doing that.

Beyang Liu:

For those listening, it's a very bare-bones white screen and vanilla font.

Sam Scott:

Don't listen to him. It's beautifully designed.

Beyang Liu:

I'm sure a lot of design.

Sam Scott:

Yeah. People on the screen, please don't try and poach our frontend developers. No, we want to stick to just the basics. I don't want to be distracted by all the UI stuff. All right. You can see, I can like log in as a user. So I logged in as [email protected]. If someone's paying attention, I didn't have to enter a password because that's out of scope on this demo.

Beyang Liu:

Well, the auth end is not part of what we're concerned about here.

Sam Scott:

It's not part of the discussion now. Those two are nicely decoupled.

Beyang Liu:

Yeah.

Sam Scott:

Yeah. So, I've got my little landing page here that's going to show me like all the repositories I can see and all the issues I can see. And so, I'm going to split my screen and have that up in one screen, and then start writing some authorization logic. Okay, so basically I have, on the right side of my screen now, the full version of my GitHub example policy. It's going to look very similar to what we just saw before, except it's been filled out with other bits and pieces.

Okay. I don't know, the main thing I want to show here is we can start playing around with this, and we'll see like the impact to this on our front end, the permissions I can see. So for example, let's just go ahead and write an allow anything rule. So I'm going to say, any user can do... How is this going to work? Can do any action on any... Let's say on any resource. I'm going to do like a nice blanket allow here. My Node app should be recompiling in the background, and my React app should be refreshing the webpage, unless I messed up. Probably messed up here, didn't I? What if I get rid of that? What if I say user can do anything? Oh, live demos.

Beyang Liu:

Yeah.

Sam Scott:

I wonder whether something-

Beyang Liu:

Live coding.

Sam Scott:

... Broke while I was doing other things and talking. Let's have a look. Oh, thank you. Oh, right. That makes sense. Okay. Okay. Okay. Okay. I can't be quite so eager. Let's just say users can read anything.

Beyang Liu:

Got it. We'll let you be that cavalier. It's like, there's no way that you'd ever want that, allow any permission to anyone.

Sam Scott:

Yeah, that sounds ludicrous. Seems like we're still getting... Oh, oh, there we go. Okay. Finally refreshed. Cool. So now, okay. So now I can see like all the data I have in here, and it's not a ton, and I can see I've got this other repository. So, I've got the Beatles Abbey Road repository, and the Monsters Inc. paperwork repository. And yeah. Kind of the nice thing is here, I can change my authorization, largely can start like seeing what the impact is going to be on my app. So, first I said that users can read anything. Let's say that users can delete anything as well, and see how we got on with that.

Beyang Liu:

So you just added an allow all for delete, and we're waiting for the app to refresh. And I assume that grayed-out delete button...

Sam Scott:

There it goes.

Beyang Liu:

Yep. There it goes. It turned red.

Sam Scott:

And so yeah, this is kind of the end to end here, authorization. I've got my authorization, logic, my policy. That's saying things like what a user can read and delete. And it's propagating all the way down to the front end to the point of listing all the repositories a user can see and what they can do within those.

Beyang Liu:

I love how clean this is. Because if this were like just embedded in your application code, at least for me, every time I make a change to that code, I'm just like staring at it, like re-rereading it, just to make sure I didn't inadvertently... I mean, we have tests and all that, but just to make double sure. But here, it's okay, it's obvious. It's all encapsulated in this nice file.

Sam Scott:

Like we were talking about earlier, I've got my user can read an issue if they're read on the parent, let's just go ahead and get rid of that. Like no, I don't want that to be true any longer, no read of issues. You're only going to be allowed to do the thing if I give you explicit information. I regret setting my refresh too slow, but there I go, our issues disappeared because the user no longer can read it.

Beyang Liu:

Wow. That's awesome.

Sam Scott:

Yeah. I mean, that's kind of like the end state, and it just kind of closes the loop of what we're talking about, which is that my dream end state is that someone can really basically build their app, and they can put an enforcement in the right place. And then, they just get to just have that fun of like deciding who can do what, how should their app work? How are things tied together? And yeah.

Beyang Liu:

So question, this is all open source? Like everything you shown so far, anyone can just embed as a dependency in their application, is that right? I guess my question is like, I feel like I should pay you some amount of money for this. What would I pay you for? And how do I do that?

Sam Scott:

This is all open end source, I mean, yeah. When we're a startup, we are ultimately here to build a successful company and a successful product. I don't know. Don't get me wrong, I love open source. I'm like a believer in it, in the beauty and the amazingness of open source, but I wouldn't say that extends as far as me saying like, I must pursue an open source company, it's like the only thing I do.

The reason we ended up there is because, I mean going back to those early conversations, people saying, I don't see how I could put this core business logic outside of my app, and the deeply entangled nature of it that needs to read that application data, so and so on.

So that led to us deciding that we must leave authorization inside the application, like the library is the best place to do it. You have enforcement, enforcement is in the app. There's nowhere else to do it. It's like you have that footprint. If you're going to do a library for authorization, and like, some people are going to embed that, I do believe the right thing for the developer is that's open source, that like you can see and control the thing that you are integrating into your app.

And so that's kind of like what led us here was like, we just felt that's the right way to solve this part of the problem. I mean, our focus right now really is just making this library as widespread and as useful as possible. But ultimately the future for us is around, how can we continue to solve this problem and more of the problem. And if the problems that we think are worth solving and the way, and the solutions we have, that we think are the right way to solve them is a service, then that's kind of what we're planning on building and commercializing, but it's sort of...

Beyang Liu:

Yeah. Makes sense.

Sam Scott:

For us, it's driven from the solving the right problems first and making sure there's a viable business model around that.

Beyang Liu:

Yeah. I mean, this is a whole can of worms discussion, because it's interesting that the predominant model for realizing revenue off of software is to offer it as a service, which it seems like backward in a way, because a lot of times the real value, I guess, comes from the actual code. The logic and then running it as a service, it's almost like you're trying to manufacture a reason to charge for it, I guess. I mean, the predominant like wisdom right now is cloud is the future, but I think cloud is the future precisely because cloud offers a viable and sustainable business model for software. You just offer it as a service on the cloud. But for me as a programmer, I still can't shake this like, oh really? That's what we're charging for, just running the software, not actually writing it and coming up with all the algorithms, and data structures, and design, and the code?

Sam Scott:

In some ways we are lucky and unlucky that that's not the shape of the problem for us. The approach we're taking, and our rationale for what we're building, is that it should live in the application. So for us to say like, we'll just manage that for you, doesn't make any sense. That's a different product. We do believe though, there is a lot of functionality that we could best offer through a service, basically. The stuff that just wouldn't make sense for it to be like embedded in this library.

The kinds of things we're thinking they span from a service that will just give you roles permissions, admin dashboards, kind of API in a box that you just get to add to your app and run with it, through to security tooling like auditing, which just comes up a ton, and it would be something that a team would otherwise have to build themselves on top of all this. They would think to figure out how to manage and store this data and process that efficiently. I think there's a wide range of value that we can offer on top of this library, we're just kind of giving everyone that foundation layer first, where it's like, just figure out how to make your app piece work well. From there, I guess we have like plenty of areas of things we want to address next.

Beyang Liu:

That makes sense. You're building this resource. You're making it available to everyone as open source, but then you naturally are going to be the experts in that resource. And you'll be the best equipped to build a software-as-a-service business to complement the value that open source provides.

Sam Scott:

And yeah, I mean, we are basically betting on the fact that I think a lot of people will kind of appreciate and respect the approach we took with the open source library, and that see that we sort of have developers trust in our minds. That's sort of approach we're taking, we're not just building a service for the sake of it, we're just trying to figure out where we'd solve the problems. Yeah.

Beyang Liu:

Yeah. That makes sense. So just to round out this whole conversation, if people are listening and they're curious about Oso, they want give it a try, where should they go?

Sam Scott:

So, you can't go wrong if you start with the website. Osohq.com. You'll see a little widget built in there that gives you kind of a little demo version of what I just did, in the website, that is actually driven from Oso itself in the browser. So, that's kind of cool.

Beyang Liu:

Nice.

Sam Scott:

Yeah. From there, you can obviously go down different rabbit holes with the product, with the documentation itself, just go and learn how to start using this. And obviously, it's open source. You can whatever, pip install oso, add Oso and get up and running. So, you can go read the docs and get running yourself, or we also have a community Slack. You can find the link for that through the website as well, where you can just come and talk to us directly and come chat about authorization, what you're trying to achieve, figure out if Oso is the right fit, ask us any questions, all that kind of stuff.

Beyang Liu:

Well, my guest today has been Sam Scott. Sam, thanks so much for being on the show.

Sam Scott:

Thank you for having me.

This transcript has been lightly edited for clarity and readability.

Start using Sourcegraph on your own code

Sourcegraph makes it easy to read, write, and fix code—even in big, complex codebases.