OAuth and OpenID Connect
The Thing I Feel Like I Knew for Years, But Not Really
Last time I tried to implement cookie-based authentication from my FastAPI series posts, and it works pretty well. But I don’t want to manage user’s credential myself. Because it’s a daunting task to maintain sensitive data. I’d rather depends on some reliable 3rd party identity provider to do the hard work for me.
This is when the OAuth2 comes to help… Or OpenID Connect to be more precisely.
It’s very easy to get confused by all the technical jargons. Just while I’m working on this post, I saw this tech news in the morning, and I quote.
OAuth is an authentication protocol that was introduced in 2006 and acts as a passwordless signing-in for many applications through social media accounts such as Facebook, Twitter, or Google.
As you can see, even for a tech savvy news website can be confused by what OAuth actually is. Although the article’s reference from the Salt does explain the whole thing correctly, and the Salt’s article also did a great job to provide educational content. I highly recommend everyone who’s trying to implement social sign-on should at least scan it once.
Anyway… OAuth…
OAuth is short for Open Authorization. It’s a specification to implement authorization process. Hence, if I’m just making a website that people can log in and use the service provided by my website. I probably don’t need to implement OAuth by myself.
So, what is it good for?
When someone want to access the services on my website without using my website directly. Like we can let people post a new article through API calls without interact with my website’s UI.
That’s the essence of authorization. We allow everyone who holds a valid token to do the things we allow them to do. Imagine we have a keycard that allows us to access certain areas or offices in the company building. That’s authorization.
But why it’s so easily get confused with “Authentication”? Because authentication and authorization usually come hand-in-hand. Like the keycards are usually our employee badge that can identify who we are, just like our ID, which is authentication. But not every keycard has identity built in. We may have temporary keycards for visitors or vendors, which just authorize the visitor to access our facilities.
So, to grant authorization we usually need to do authentication first. In the keycard analogy, we were first become our company’s employee (register). And we identify ourselves to HR or whoever make our employee badge (authentication/login). Then they setup the badge for us (authorization). Now we can use the badge (token) to access our office or sneak some snacks from the pantry or something.
And someone could also sneak in if they collect my keycard. Because it’s an authorized token, the door doesn’t really need to recognize me, it unlocks the door just because it’s a valid token. It surely knows who actually owns the token, but the door wouldn’t ask who’s using it.
And what authentication is a process to identify that someone is actually who they claim they are. Like the HR may ask me to provide my ID or licence or something else to make sure I’m actually the registered employee of the company before they can safely hand the employee badge over to me.
As you can see, although OAuth is a process to do authorization, but there’s also an authentication step (log into IdP). That’s why companies like Google or Facebook start to realize if people have to login anyway (at least the first time they go through the OAuth process), and we got all the user’s information. Why not just integrate the OAuth flow as social sign-on solution?
That’s the time when OAuth became so confusing…
The idea is… If the user is authenticated by the social media company, we can trust it as a real person (if Google and Facebook cannot identify them, we probably wouldn’t do a better job of it). So, we can use the token as a prove to login the user on our own website.
After years, each major plyers in the social media scene developed their own way for social sign-on solution built on top of OAuth flow just based on this. And it became a pain to implement different way to allow user to login from different social media account. And if we are not careful enough, we might cause some serious security problems.
That’s why we have OpenID Connect protocol today. We first sort out chaotic of everyone have their own authorization flow. Now a new challenge to do authentication…
OpenID Connect is just a relatively thin layer built on top of the existing OAuth2 specification. The whole auth process is almost identical to the end user. And to integrate the flow into existing OAuth2 flow as a client application is also pretty simple.
The major difference between vanilla OAuth2 and OAuth2 with OpenID Connect is… In OAuth2 you will receive an access_token
. While with OpenID Connect you will receive an id_token
and an access_token
.
The access_token
is our keycard, the format may vary, it can either be a random look-alike string, or a JWT (JSON web token) depends on the implementation. So, what’s an id_token
? The id_token
is a JWT, which is signed by the issuer (IdP) that can prove its authenticity. And it usually comes with the user’s basic information, but it’s not required. That’s it.
As you can see, the id_token
actually serves very little purpose at the first sight. The user’s information is not even required to be presented in the token itself. It just tells you when did the user signed in, and the IdP kind of says “Yes, I concur.”…
Because id_token
seems so irrelevant, one can almost certainly say “Yes the user had logged in, because I’ve got the valid access token that can retrieve user’s data.”. And use the access_token
directly. And that’s a huge mistake to simply treat it as just another source for user’s data. It exists for actual security reason.
This is basically what the loophole described in the Salt’s article. In case you missed it from the link at beginning of this post.
TLDR; Don’t trust anything from the response if you are going to use the access_token
as the only prove to login your own service. And make sure you validate the id_token
if you follow the OpenID Connect protocol.
Anyway… Enough talking…
Next time, I’ll implement OpenID Connect flow (as a client app) that allows my user to login with their Google account. Actually, I’ve done the coding part. Just because the intertwine of OAuth and OpenID Connect are so complicated. So, I figured that I have to spend a little bit more time to make sure I’m fully understand the better way to do it (Even though I’ve done that for many times, I still find it quite hard to explain how it works and how to use it properly).
OAuth and OpenID connect are open specifications. They are supposed to provide a standard way to implement and integrate depends on your position (relaying party or identity provider / service provider). Does not necessarily mean there’s only one way to do it.
Like what I’ve been through the basic authorization. Passing credential in the request header is also a common way to do authorization in the past and can still be spotted in the wild especially for service account.
And there’s also multiple way to achieve social sign-on. Like if you go to Google’s documentation, they actually provide three different ways to do 3rd party authentication, one of them is deprecated, one is OpenID Connect, the other is their own implementation.
So, it's a process, and it will never end. All I’ve demonstrated is one way to do it but not THE way to do it. Keep exploring, cheers.