
OAuth 2.0 Security Best Current Practice - mooreds
https://tools.ietf.org/html/draft-ietf-oauth-security-topics-15
======
guessmyname
I implemented more than a dozen OAuth integrations last year with multiple
American and Chinese companies and oh boy it was painful.

I do not know why so many engineers end up reading a clear specification
document like RFC-6749 [1] and then ignore 80% of the instructions. I had to
deal with so many weird bugs and bad OAuth server implementations, I lost
count of how many emails went back and forth trying to make sense of
unexpected behavior.

Even Apple engineers got it wrong. They decided to create their own thing
based on OpenID Connect for “Sign In With Apple” [2]. OpenID had to write an
open letter [3] explaining the repercussions of their changes and fortunately
were able to convince Apple to fix the implementation [4].

OpenID was lucky though, they had some leverage, but a _no-one_ like me
couldn’t possibly convince a gigantic conglomerate like Tencent to fix their
web API. Talking with Tencent engineers has been one of the worst experiences
in my career. The company apparently has a culture of constant job rotations,
engineers are assigned projects for short periods of time with bonuses for
early completion which encourage them to deploy half-finished code before
moving to something else.

[1] [https://tools.ietf.org/html/rfc6749](https://tools.ietf.org/html/rfc6749)

[2] [https://developer.apple.com/sign-in-with-
apple/](https://developer.apple.com/sign-in-with-apple/)

[3] [https://openid.net/2019/06/27/open-letter-from-the-openid-
fo...](https://openid.net/2019/06/27/open-letter-from-the-openid-foundation-
to-apple-regarding-sign-in-with-apple/)

[4] [https://openid.net/2019/09/30/apple-successfully-
implements-...](https://openid.net/2019/09/30/apple-successfully-implements-
openid-connect-with-sign-in-with-apple/)

~~~
polskibus
I always wonder why do companies have to implement oauth2/open id connect. It
seems like a big waste in tech to spend so much time implementing the same
things by different companies.

can you tell me if there is a good drop in component that I can add to my
product and integrate easily to get oauth2/open id connect? I heard good
things about identity server but would appreciate if you could share your
opinion on it.

~~~
bingo_cannon
I've recently tried out
Keycloak([https://www.keycloak.org/](https://www.keycloak.org/)) and have been
impressed with it. Saved at least a few weeks on a personal project. It does
have a learning curve though.

~~~
znpy
This, so much.

I've been tasked with implementing oauth/openid at work and in about one month
in spare time i was able to read rfc 6749, install keycloak, configure it,
create a client, create a very basic app (~80 lines of python and flask) and
log in via oauth/openid with user information and groups pulled via LDAP.

Keycloak is really a game changer.

This presentation is very interesting:
[https://www.youtube.com/watch?v=FyVHNJNriUQ](https://www.youtube.com/watch?v=FyVHNJNriUQ)

------
drivebycomment
This is all good and useful, but I wish OAuth folks would fix the bugs in the
spec like, e.g.

"The authorization server MAY issue a new refresh token, in which case the
client MUST discard the old refresh token and replace it with the new refresh
token. The authorization server MAY revoke the old refresh token after issuing
a new refresh token to the client."

This sounds reasonable on the surface, and technically it might be correct
(depending on your interpretation of the words). But if someone naively
follows this instruction to implement the server - issue a new refresh token
and revoke the old one in the same refresh request at the server, what happens
is when the client doesn't receive the new refresh token due to any transient
failure, the client effectively loses its authorization, since the old refresh
token is revoked and they didn't get the new one. Thus the protocol becomes
"leaky" \- you lose users because of transient errors.

i.e. "after issuing a new refresh token to the client" needs to be "after the
new refresh token is being used at least once", or otherwise invent some other
way to ensure the new refresh token is correctly received at the client before
revoking the old.

~~~
codebje
"… or otherwise invent some other way to ensure the new refresh token is
correctly received at the client before revoking the old."

These sorts of details will typically wind up in an implementation report
document. It's rare that an IETF protocol specification document will attempt
to pre-determine the solution to all such implementation details up front, and
IMO, not good when they do.

In some contexts, it may be much better to require the application to re-
obtain resource owner authorisation than to allow a replay of a refresh token.
In others, it may be much better to avoid requiring resource owner
authorisation. What you see as a bug, others would see as a critical feature.

------
deng
To this day I have no idea how one should handle client secrets in (F)OSS
applications, and I'm often wondering if I'm the only one. I guess what this
text says in 4.13 is "just don't put it somewhere for anyone to see", which
means that the only solution is to make the id and secret configurable and let
the _user_ register the application with its OAuth provider, which of course
most users wouldn't know how to do. As a result, applications like Thunderbird
simply put the secret in the code with a comment above it "please don't copy
these values for your own application". I really don't mean to shame Mozilla,
what else are they supposed to do?

~~~
nicolaslem
From my understanding the best practice for applications that run on clients'
machines (Javascript SPA, mobile app, email client) is to not use a client
secret at all. Just use a client id and assume that anyone can reuse it.

Of course that is if the OAuth provider allows it.

~~~
deng
> Of course that is if the OAuth provider allows it.

That's the catch. Last time I checked, at least Google didn't. So how can you
write a (F)OSS email application for accessing GMail via OAuth2, without
putting the secrets into the code (which Google also forbids)?

~~~
niftich
In this situation, their guidance says to embed the secret, because in this
context it's obviously not a secret. Here's the current page [1]; here's the
earliest Archive.org snapshot of its one-earlier predecessor page from 2015
[2] -- the advice has been consistent.

[1]
[https://developers.google.com/identity/protocols/oauth2/nati...](https://developers.google.com/identity/protocols/oauth2/native-
app) [2]
[https://web.archive.org/web/20150520223809/https://developer...](https://web.archive.org/web/20150520223809/https://developers.google.com/identity/protocols/OAuth2InstalledApp)

~~~
deng
No, Google is not consistent in the slightest, because their terms of service
directly contradict this statement:

"Developer credentials (such as passwords, keys, and client IDs) are intended
to be used by you and identify your API Client. You will keep your credentials
confidential and make reasonable efforts to prevent and discourage other API
Clients from using your credentials. Developer credentials may not be embedded
in open source projects."

From:
[https://developers.google.com/terms](https://developers.google.com/terms)

------
dwaite
It is probably worth pointing out on this thread that there is a brand new
draft (not yet on the working group) attempting to combine extensions and the
best practices of OAuth (including these security practices) into a new "2.1"
version.

[https://tools.ietf.org/html/draft-parecki-
oauth-v2-1-02](https://tools.ietf.org/html/draft-parecki-oauth-v2-1-02)

------
abhishektwr
I need to read this draft RFC a few times before I can grasp it completely.
There is an existing RFC drafted in 2013 with a focus on OAuth 2.0 threat
model and security considerations [1], and it looks like this new RFC is
making more specific recommendations on top of it. May be read them together.

To be honest, I was wishing for OAuth 2.5 if not OAuth 3.0 to consolidate
already fragmented OAuth 2.0 spec and landscape [2]. At this stage, there are
too many draft proposals and a majority of them led by vendors with some
interest in standardizing their implementations.

For example, this RFC suggests restricting issued access token to one resource
at a time (using audience parameter). Well with Microservices landscape this
gets really challenging. Your client application may be interacting with
multiple resources. Neither OpenID Connect nor OAuth 2.0 offer solutions to
issue multiple access tokens (not yet). An API Gateway may be a solution but
still so much ambiguity.

I think OpenID Community has done a better job to organize their
specifications and working groups [3]. If you go on their specification page
it tabulates really well what spec is final, currently under implementation,
draft, or obsolete. Still, big vendors influence agenda and direction.

(Disclaimer: I am the founder of [https://axioms.io/](https://axioms.io/)
which OAuth 2/OpenID Connect compliant identity management platform)

[1]:
[https://tools.ietf.org/html/rfc6819](https://tools.ietf.org/html/rfc6819)

[2]: RFC 6749, RFC 6750, RFC 6819, RFC 7662, RFC 7009, RFC 7519, RFC 8414, RFC
7591, RFC 7592, and 20 more.

[3]:
[https://openid.net/developers/specs/](https://openid.net/developers/specs/)

~~~
niftich
As posted by someone downthread [1], there's an ongoing effort to update the
OAuth 2.0 spec with changes since, lessons learned, and best practices [2], in
what's currently being called OAuth 2.1. Some more rationale and resources on
oauth.net [3].

[1]
[https://news.ycombinator.com/item?id=23083245](https://news.ycombinator.com/item?id=23083245)
[2] [https://tools.ietf.org/html/draft-parecki-
oauth-v2-1-02](https://tools.ietf.org/html/draft-parecki-oauth-v2-1-02) [3]
[https://oauth.net/2.1/](https://oauth.net/2.1/)

~~~
abhishektwr
Thanks for the pointer. I am not sure if OAuth 2.1 is part of working group
yet. Nonetheless, a good consolidated read compared to reading 20 different
RFC specs.

------
anderspitman
> Clients MUST NOT pass access tokens in a URI query parameter

I've been wondering about this lately. This makes sense from a security
perspective, but the primary alternative is setting a header like
Authorization: Bearer, which makes your request subject to browser cross-
origin restrictions, and all the fun that comes with CORS. In my case, the
extra round-trip required for the CORS preflight in this situation is simply a
non-starter for my application.

It would be nice if there was an escape hatch for developers who understand
the risks. More background in this SO question I asked a couple days ago:

[https://stackoverflow.com/q/61563348/943814](https://stackoverflow.com/q/61563348/943814)

~~~
malinens
put it in a cookie (secure samesite) or in request body

~~~
anderspitman
Can you give more details on how you'd use a cookie here? SameSite=Strict/Lax
can't be used cross domain, and none is no good for mutating requests due to
CSRF.

Request body works, but it forces you to split your API if you want to be
cache friendly. What I mean is ideally you want public data to be GETable and
thus cacheable. In the system I'm building, any given path can change back and
forth from being public vs requiring authorization, so if I use requests
bodies (ie POSTs), I would need to detect whether the data is public or not
before making the request and choose between GET or POST at request time. That
might not actually be that bad; I'll have to think about it more.

------
dijital
Worth bearing in mind:

> This Internet-Draft is submitted in full conformance with the provisions of
> BCP 78 and BCP 79.

> ...

> It is inappropriate to use Internet-Drafts as reference material or to cite
> them other than as "work in progress."

~~~
DCKing
As a case in point: [https://tools.ietf.org/html/draft-wkumari-not-a-
draft-05](https://tools.ietf.org/html/draft-wkumari-not-a-draft-05)

I think publishing an IETF RFC on security best practices is hard, but I hope
these authors manage to pull through

------
kerkeslager
If there was one perfect way to do third-party auth, we wouldn't need a
standard, because all the big companies would be doing it, and the smaller
companies would do it.

The problem is, there's a bunch of decisions with auth, which have to be made,
but aren't really important. What should the name of the auth token header be?
What should be the format of the responses? These decisions are like deciding
what side of the road to drive on: it doesn't matter which side of the road
you drive on, as long as everyone drives on the same side of the road. The
function of a standard is to decide what side of the road everyone drives on.

OAuth isn't a standard. It's just a description of all the various homegrown
third-party auth systems that anyone has implemented over HTTP, with only the
absolute worst patterns weeded out. None of the shareholders wanted to re-
implement their third-party auth, so they just made sure their flavor of auth
made it into the standard. It's like if the Europeans and the Americans got
together to standardize the side of the road that everyone drives on, and the
standard they came up with is "You have two options for which side of the road
to drive on, the right or the left."

Until a group of visionaries with enough clout to make the world fall in line
creates an actual standard, OAuth is going to continue to be crap. And there's
strong disincentive to do that: if you agree to conform to a standard that
isn't exactly what you've already implemented, then that means you have to
reimplement. A few years' pain conforming everyone to a standard would
significantly drive humanity forward--an incomprehensible amount of developer
hours have been spent writing custom OAuth integrations, and an actual
standard would allow us to write libraries around it that everyone could use.
But corporations don't care about pushing humanity forward when it's contrary
to their bottom line.

------
tptacek
It's not structurally all that great; it opens with a long section of
recommendations backed by citations to later "attack model" sections in the
text, which themselves include disjoint lists of recommendations.

------
sytringy05
I've been working with OAuth 2 for 7 years and I still don't really understand
all the dark corners of the spec. Good to see Resource Owner grant type get
called out for a "Do not use", although I dont think using it in a private,
server side context is off the cards...

------
jzer0cool
Is it weird I like reading such specs? Many people find it dense, but I find
it rewarding to read. What CS job would be more tuned to spending time doing
this leisure?

~~~
ta17711771
Sysadmin/devops

------
znpy
Since we're talking oauth/openid: does anybody know if there's a way to get
the OpenID spec in a format that is nicely formatted for printing?

(ideally, just like rfc 6749...)

------
patwillson22
The road to hell is paved with best practices.

