Hey folks I'm Nate Barbettini, product manager
here at Okta and I'm here with Aaron Parecki. Thanks. I'm Aaron Parecki. I'm a developer advocate at Okta and
also a member of the OAuth Working Group. So I've been seeing the OAuth working
group talking about the implicit flow talking about some of the best
practices changing around that, I know you're really involved in that so I'm
kind of curious what what's going on. Yeah sure thing. So I've been involved in the working group
and part of the part of the group that is working on the
specific guidance around the implicit flow now and some the changes around that. So it's something that's relatively
recently been part of the discussions in the group part of the
last couple of meetings of the group as well as discussions on the
mailing list things like that. And what what's the impetus for the
discussion what kicked it off like is there a somebody find a vulnerability in
the implicit flow or like why are we talking about this now? Yeah yeah sure. So there's no new vulnerability or
anything like there's no significant event that even
necessarily triggered this. It's more that the implicit flow has
never really been secure from the beginning and everybody kind
of knew that. But at the time we
didn't really have any alternatives. So you know think in like 2010
when mobile app platforms were brand new and single page apps were just
starting to become a thing right. And --. That's a long time ago. It's a long time ago. We kind of just take
these things for granted now. But at that time in that
ecosystem browsers worked very differently, and we didn't have a lot of good tools
available to browsers at the time to do things sort of properly --
like the regular OAuth way. And because of that people still wanted to
do OAuth in a browser based app in pure JavaScript. And so we needed something because
you couldn't you couldn't do the regular auth code flow in
the browser at the time. For anyone who's not not super deep in
the OAuth world why is it that we can't do the auth code flow
in a browser or couldn't? Without getting too far down in the
weeds, the basic reason was that cross-domain requests were not allowed
in browsers for security reasons for a very long time. And as web development evolved
and apps got more complicated and people are using CDNs for things
and app deployments are getting more complicated, we obviously need a way
to do cross-domain and requests and the whole cross-origin resource sharing
policies started popping up in browsers and there now are good
tools to enable specifically when you want to do a cross-domain post
request to allow it from only certain places than others right. So on my server I can say
these specific places -- these origins are allowed to make
across domain request. Otherwise keep it locked down and
you can't make a request. Exactly. Yeah. And the whole the whole way that the
regular OAuth flow works is by doing a POST request -- you know the very
last step is is the app to the POST request over to the token
endpoint with authorization code that it has, and it gets
back and access token. That post request, if your OAuth server
is on a different domain than your app, then that is
a cross-origin and request. Right. And that can only happen if
the OAuth server says it's okay. And, prior to the sort of new
way browsers are working that wasn't even possible in browsers. Got it. So way back then we kind of said well
if you want to do OAuth in a browser based app, we'll kind of let
you cheat around the system and you don't have to use a client secret, you're
just going to do what we call the Implicit flow and you
just use the client ID. Yeah you just use a client ID,
and more importantly it returns the access token in the redirect from the
authorization server and bypasses that entire second step. So it looks simpler at the surface
as well because you know there's fewer steps. It seems more more direct. Just for curiosity why do
we have that extra step. Why why don't we just
do the simpler route? Yeah. So the simpler route of just
returning the access token you know immediately in the redirect -- the downside
is that there's more ways that can sort of go wrong. The reason that a lot of the
attacks happen and a lot of vulnerabilities happen is because there are a bunch
of different ways that that redirect step can fail. If you imagine that like you know
the whole way that captive Wi-Fi portals work, right? You're like "hey I'm gonna
go to example dot com and then instead you get the
captive login page. You're on boingo wireless 2
dot com or something. Exactly. So when the access token
is returned in that redirect step, if that's intercepted it's basically
just game over at that point, because in OAuth, an access token can
just be used by anybody who has. It's called a Bearer Token. Right. So if an attacker can steal the
access token they can then make API requests and nobody would ever know
that that is happening from an attacker. So we have this extra steps the access
token doesn't come back in the in the redirect, we get a code back, and
then you have to make an additional request -- a POST request to exchange
the code for an access token. I think what what still
confuses me and some people is that it seems like if
you're not-- if you don't trust the network on the redirect how come
you trust the network on the POST request? It seems like it's
still maybe has the same problem. Yeah. So it's a it's subtle. As we all know with security there
is no such thing as 100% secure. Right. Everything is about mitigating risk
and you're playing a numbers game. Cryptography is
not perfectly secure. Cryptography is based on the idea that
it is very hard to guess numbers. Right? Right. And we use we use large enough
numbers where it is practically impossible but it is still theoretically possible
for someone to crack it. So the same thing is true here
right, where you obviously can't solve everything but you can
eliminate the easy attacks. And one of the easiest attacks
is stealing that redirect because there's more ways to steal it than
there are ways to intercept that POST request. Right. Somebody could... even just logging of URIs
that are going by. You could see if the access token is
in the URI in the query string or something and somebody is just logging
every request that goes through some gateway or something they could
even inadvertently capture the access token. Inadvertently for sure. Another great example is browser extensions
because that is now code running in the browser that the
app developer isn't even aware of. Which are probably allowed to
see the address bar. Certainly If you just click "Sure give it
all permissions" when you installed it. Absolutely be able to watch the URL
and watch for stuff to appear there. Browsers now
are more featureful. You can sign into your Google account
in your Chrome browser and now your web history is synced to Google, which
now means if there's an access token in the URL now the
access gets sent up to Google. And then maybe back down
to your other computers. Now there's multiple copies of it
floating around which are even more opportunities to steal it. And that's all a very different
threat profile than intercepting that POST request that the browser makes. Gotcha. So coming back to what's changing
-- for a long time the implicit flow is how we did
OAuth in the browser. So what is changing? What's the new proposal on the table? So the implicit flow was created in
a time where browser security worked -- browsers worked differently and under
constraints that are mostly no longer relevant. So the other main thing that has changed
is browsers used to not be able to modify the path part of the
URL in JavaScript without triggering a page reload. If you're building a single
page app you don't want the page to reload if you're
modifying the address bar. Obviously as soon as you finish the
redirect you want to remove the stuff from the query string. So you want JavaScript
to clear that out. Now there is a fantastic API for
it, the Session History Management API. So we have all these tools available to
us now that actually enable us to do OAuth more securely in a browser
which was not true 10 years ago. So the landscape has just slowly
evolved and that is the main motivator for this new guidance. Which is that the Implicit
flow has always been a -- I don't wanna say hack
-- but less than ideal solution. And it's just there wasn't a
good story to tell otherwise. Just like well right now this
is the best we can do. This is the best we can do
right now given the current constraints. Ten years later, tools have gotten
better, ecosystem has changed, those constraints no longer apply. So all we needed to do was just
to reevaluate the spec and re-evaluate say like hey does this still make sense. And the answer now is no
it doesn't make sense anymore. So the other main thing that changed
is sort of in parallel to this, the mobile app
landscape has been evolving. A little bit of evolution
of that since 2010 right. Just a little bit. Yeah. But interestingly also in
2010 the spec was recommending the implicit flow for mobile
apps, because it wasn't obvious why -- well you couldn't use a secret
mobile apps, we knew that from the beginning. And if you can't use the
secret then the implicit flow was a natural way to not use the
secret and do the OAuth flow. We call those public clients right. Public clients where you're not -- you
can't guarantee that the secret be kept safe. Exactly. Back in 2010, the implicit
flow was recommended for mobile apps but then very quickly that
started changing and the PKCE extension was developed. So that was something that was created
specifically for mobile apps as a better solution to doing OAuth on
mobile for all these same reasons. So PKCE kind of fits fits a little
gap there which is I can use the authorization code flow which is the two
step process where I get a code and then I have to exchange it. But normally that requires a secret. The way PKCE solves it is instead
of using a preconfigured secret that's shared across all installs of the app it
uses a it makes up a new secret on the fly every time. So it's like a dynamic secret. Yeah. So every time an app wants to
initiate the OAuth flow it just makes up a new secret, hashes it, and then
does the regular OAuth flow with that additional hash value and gets the
access token in the back channel. So the PKCE... can you call it a spec? the PKCE extension makes it possible
to securely do the authorization code flow on a mobile device without a
secret but still ensure that someone else couldn't intercept the code or steal it
from you or try to beat you to getting the access token
from it or something. Yeah. So that's been the best practice recommendation
in mobile for a couple of years now, right? Several years. Yeah. PKCE is an RFC it's a separate
RFC it's an extension to OAuth 2.0. It's been working for several years now
it's been in production a bunch of places. So it was created for mobile
apps but it turns out it's useful for any public client. Where you can't store a secret but you
still want to use the best flow which is the authorization code flow. Yeah exactly. So now what we're seeing is
because browsers can make cross-domain POST requests and because they can modify
the address bar they can now actually just use PKCE as written
with no changes to the spec. No additional spec needed. So the auth code flow plus PKCE is
now a great solution for browser based apps. So the proposal in the OAuth working group
is basically just -- hey we have this spec PKCE, it works well for
mobile, the landscape has changed in browsers, why don't we use it in
browsers too, and it turns out there's there's no reason why we can't. Yeah. PKCE is useful in browser based apps
just like it is a mobile apps. That is essentially what these two
new specs are are saying. Security Recommendations and the Browser
Based Apps spec which is the one I'm writing. What a lot of people are wondering is,
is this something that we should go out and just go change
immediately like should I go. PKCE-ify all of my apps tomorrow? If you have apps that exist that
are using the implicit flow, there's no new risks to you. You have always been in a
sort of risky situation hopefully you've addressed those risks by doing
all the other protections you can against attacks. None of that has changed. So as long as you are doing things
properly and have built a secure app and aren't using you know random
third party JavaScripts hosted on CDNs from questionable domains
then you're probably fine. No need to tear everything out and
rip it out and start over. Eventually yes. Roll it into your sort of natural
product lifecycle migration that you are going to be doing anyway. Building new apps absolutely
use PKCE going forward. Gotcha. So this isn't like a CVE
found zero day need to go replace this immediately, but it's
something to think about. Yeah there's no CVE for this. There was no vulnerability found. So I guess coming coming at the
question from a different way too... If I do switch to PKCE using
the authorization code flow in my browser apps, does that mean that my
browser app is just 100% secure? Like I don't have to
worry about any other security? Is it rock solid? Yeah. Good questions. This is one of the sort of
unfortunate things about browser based apps which is that there isn't really
a secure storage API in browsers. Which means at the end of both the
implicit flow and at the end of the auth code plus PKCE the
result is the same. You have an access token. And there isn't a good way
to store that in a browser. There isn't a secure way to store it. Anywhere you put it is accessible to
any other JavaScript on the page which means it's accessible
to browser extensions. And if you have third party scripts on
the page that you don't know what they're doing, they could also see that
data and PKCE vs Implicit doesn't change that. What PKCE does solve is
protecting that redirect step. So it is more secure, but
it is not perfectly secure. Because again there is no such
thing as perfect security anyway. Until we have a secure API
in browsers to store secrets that are only accessible to the single
origin or whatever it is, that will always be the case. So there's another thing to keep in
mind here which is that this guidance is only really applicable to the
situation where you have a pure JavaScript app served by
a static web server. So think like hosting
HTML on Amazon S3. I've got React loaded straight
from my CDN or something. Exactly. Yeah. That server, all it does is
send a file to your browser. Right. It can't do anything else. Even if you are using a single
page app framework like React and Angular, it is often being hosted and
served from a dynamic web server. A lot of times it might be like
Spring Boot on the back end or ASP.net or PHP powering the API and
then maybe like serving the files. Yeah exactly. And in those cases, you do the OAuth
flow on the server where the server is the thing that exchanges the
auth code for the access token. And that lets you keep that on the
server where you can securely store it and then you just maintain
a session to the browser. And that session cookie can be locked
down because there are good API for session cookies where you can limit them
to not even be visible by JavaScript for example which means
nobody can steal it. And that is the most secure
way you can do it. Keep a single communication channel from
your single page app to your server, all the OAuth is managed at
the server and that's where the access token lives and that's the thing making
API requests out to your API is that your app needs to hit. So to recap here a little bit. The proposal that you're working on
in the OAuth working group is basically plugging one of
the gaps that. Something could get stolen before now,
can no longer get stolen. That's a distinct improvement in the
overall security of your browser based application. Yeah but it is worth pointing out
that plugging that gap still leaves plenty of other gaps, like browsers
are really leaky browsers are really insecure. Yeah. What are some of the other things
that people should be thinking about to keep browser based apps secure? It's things like, make sure you know
exactly what code is running on the page. Don't just load random JavaScript
from CDNs that you don't know. Definitely use HTTPS, like none of
this is secure without HTTPS. Use Let's Encrypt. You can get you get a free cert now There's no reason not to anymore. If you are for sure using HTTPS
everywhere set a long lived HSTS policy where it forces the browser to lock onto
HTTPS for 6 months or whatever it is because you know your website's
always gonna be on HTTPS. Yep. Should people think
about doing Content Security Policy on their pages? Yeah absolutely. Have a good content security policy so
that you can better know what code is running on the page. There's a whole list of the kinds
of things on the OWASP that's. Open Web Application
Security Project. Yeah exactly yeah. OWASP and we'll put that on the screen. OWASP. Or maybe this way. OWASP And that is a fantastic resource for web app security. If you are building a pure
Javascript app with no server-side component, and you're doing OAuth in the browser,
or dealing with any sort of credentials of any sort, definitely read all
of that and do all of those things. Well if you got to the end of
this video and you're still here, thank you for watching. If none of this OAuth stuff makes
sense to you or you're struggling with the jargon check out my video called
OAuth and OpenID Connect in Plain English we'll put a link to
it down in the description. Also have a fun talk I gave at
Oktane 19 about all the different ways OAuth can go wrong, so to take a
look at that if you're interested and I've got a blog post which talks about
how exactly to do auth code flow and PKCE in a browser. It does not use any frameworks, it
is just in pure JavaScript to demonstrate exactly how all
these pieces work. Very cool. Thanks for watching.