#33: OAuth 2.0: safe, password-free authorization
OAuth 2.0 is a standardized authorization protocol. In this episode, I’ll explain just one use case of it: the authorization code
flow. It allows server-side application to act on behalf of a user of another service. For example, a 3rd party application can post on Twitter on your account. Historically, to do this, this application must have had your Twitter credentials stored. Not only you had to reveal your Twitter password, but also that application must store it in plain text. Such an approach has multiple flaws. First of all, if the application is not entirely honest, it can now do anything on your behalf. Including changing your password and stealing your online account. But even if you trust the 3rd party application, it can still be hacked. Your password, together with thousands or millions of others, is compromised.
OAuth tries to solve all these problems. The 3rd party application receives an access token. It allows performing only certain actions on your behalf and can be revoked at any time. It’s not your password and you don’t even reveal your login!
OK, before we continue, let’s clarify a few terms. First of all let’s distinguish authentication and authorization. Authentication is the process of proving your identity. When you authenticate against, for example, Google, Google knows who you are. Authorization, on the other hand, is giving someone access to your stuff. The OAuth term for stuff is resource. And when resource is yours, you are the resource owner.
Technically a 3rd party application can post on your Twitter feed without knowing who you are! Not knowing your e-mail or login. Because you authorized that application to post tweets only. But not reading your personal profile. OAuth 2.0 is only about authorization, never about authentication. It’s somewhat confusing, because often OAuth is misused for authentication purposes. Every time you see “login with Google” or “with Facebook”, you actually see OAuth authorization. But the read-only resource you are granting access to is your own e-mail address, photo, etc.
OK, resource is your stuff, you are the owner of it. The resources are kept on the resource server. Twitter is such a server. There’s also an authorization server. It may, or may not be the same as a resource server. And finally, there is a client. Can you guess who the client is? Well, it’s the 3rd party application that acts on your behalf.
How does all this work in real life?
Well, let’s say an application wants to post on Twitter on your behalf.
It first asks you to grant permissions to that particular resource.
Posting tweets is a resource.
You are now redirected to Twitter in your browser.
If you are not yet logged in, you have to do it first.
Then, Twitter shows a popup asking for your confirmation.
Do you really want to grant access to this resource to that application?
If you accept, lots of magic happens.
The browser redirects you back to the 3rd party application.
In the URL you’ll find and authorization_code
.
A short-lived, temporary code that’s useless on its own.
The 3rd party takes that code and makes a backend call to Twitter.
Twitter sends you back a real, useful access_token
.
This way, the browser never sees the real token, only meaningless authorization code.
You should treat access token
as a password to this particular Twitter account.
The only thing you can do with that password is posting.
You can’t see or change the real password, see user’s e-mail address, etc.
Unless, of course, you didn’t grant these permissions as well.
Thanks for listening, bye!
GitHub OAuth 2.0 Flow
Making authorization request:
http https://github.com/login/oauth/authorize \
client_id==CLIENT__ID \
scope==read:user state=123
Callback to your own application:
https://256.nurkiewicz.com/33/callback?code=AUTHORIZATION_CODE&state=abc123
Backend call to get access_token
knowing authorization_code
, client_id
and client_secret
:
http -v https://github.com/login/oauth/access_token \
client_id=CLIENT__ID \
client_secret=CLIENT_SECRET \
code=AUTHORIZATION_CODE
Calling API using token to obtain user’s e-mail:
http https://api.github.com/user/emails \
Authorization:"Bearer ACCESS_TOKEN" | jq -r '.[].email'