Authentication & authorization - what gives?
You think you're hot shit and now you want to know some stuff about authentication and authorization. Maybe start implementing. You want it all.
Disclaimer: The below blog post was written by me for me, and might (and probably does!) contain errors. Don't rely on anything below as fact, from now you're on your own.
What we have
This is typically what you see when you visit pages attempting to explain authentication & authorization:
The above image specifically covers the Google OAuth 2.0 flow, using Google as an OpenID Connect Provider. This truly is the future, right? Right? Right.
Another way of describing the flow is from the OAuth 2.0 spec:
+--------+ +---------------+ | |--(A)- Authorization Request ->| Resource | | |<-(B)-- Authorization Grant ---| Owner | | | +---------------+ | | +---------------+ | |--(C)-- Authorization Grant -->| Authorization | | Client |<-(D)----- Access Token -------| Server | | | +---------------+ | | +---------------+ | |--(E)----- Access Token ------>| Resource | | |<-(F)--- Protected Resource ---| Server | +--------+ +---------------+
The images leave a lot to the imagination, but on a high level they show authentication and authorization information being exchanged.
We need to know more about all the moving parts!
One way of authenticating is using OpenID Connect, it's the third generation of OpenID - the first two being OpenID Authentication 1.X, and OpenID Authentication 2.0.
The two old versions are specific schemes for authenticating users, but were "unnecessarily complicated". Since everyone is using OAuth 2, OpenID Connect was implemented to run on top of it - or as the introduction to the spec states:
... a simple identity layer on top of the OAuth 2.0 protocol
OpenID Connect is used by a lot of organizations, which lend their authentication service powers (called OpenID Provider - OP) to our servers (called Relying Party - RP).
Honest question: Why couldn't they just have called it OpenID 3.0 for OAuth 2.0 or something? When running across "OpenID 2.0" and then something called "OpenID Connect", naturally you're going to think that the "2.0" is newer harder better faster stronger.
OpenID Connect is not the only game in town, Facebook Connect is another major player.
You can also try to roll your own authentication service, and if you do that you're not necessarily constrained to the requirements of OpenID Connect. It's not a bad idea to be heavily inspired by the work of geniuses, though.
Let's talk about OAuth 2.0 baby. Let's talk about you and me. Let's talk about all the good things, and the bad things.
Instead of using the terms OpenID Provider and Relying Party, the OAuth 2.0 spec uses
|Resource owner||Capable of granting access, sometimes an end-user|
|Resource server||Has resources accessible after presenting an access token|
|Client||An application (server) making requests on behalf of the resource owner|
|Authorization server||Issues tokens after authentication and authorization|
It goes on stating "The interaction between the authorization server and resource server is beyond the scope of this specification. The authorization server may be the same server as the resource server or a separate entity.""
An authorization grant is the "... resource owner's authorization (to access its protected resources) used by the client to obtain an access token"
There are four grants types defined in the spec
- Authorization Code
- Resource Owner Password Credentials
- Client Credentials.
Each grant has an associated Flow, which are ways of obtaining tokens used for authorization after authenticating a user, the most common being authorization code flow, and implicit flow.
Typically involves a browser (user agent), a web server (client), a resource owner (user), and an authorization server.
Explained in detail in section 4.1 of the spec, summarized below:
- The client (server) redirects the UA to the authorization server.
- The authorization server authenticates the user and asks the user to grant access.
- If access is granted the authorization server redirects the user back to the client (server).
- The client (server) requests an access token using the authorization code received in step 3, the redirection URI is also sent to the authorization server for validation.
- The client is authenticated on the authorization server using the authorization code and redirect URI. If valid, the authorization gives the client an access token (and optionally a refresh token).
Summarized means that a lot of detail was left out. Read the spec!
In this flow, the access token never leaves the client (server), instead the client is connected to the UA/user via e.g. sessions.
I guess the access token can be exposed to the UA anyway, if the implementation chooses to do that. The takeaway is that the client uses credentials (typically client secret) issued by the authorization server, that should NOT be used in the implicit flow. Otherwise it wouldn't be a secret.
Mixin' it up
OpenID Connect runs on top of OAuth 2.0 - always keep that in mind when reading about these two separate specifications!
The concepts of the different specs and auxiliary technologies like JWT are often presented as one and the same by third parties (blogs, etc) and one needs to keep that in mind.
OpenID Connect gives you the convenient ID Token, which can be used in parallel with the OAuth 2.0 Access Token, or separately!
All of these are (usually) JWTs. Basically they contain claims, and (AFAIK) those claims should only ever be trusted if they are digitally signed by the issuer using e.g. JWS, and that signature should always be verified by anyone about to trust those claims (e.g. a resource server).
Here's one place to play around with JWTs and different types of signatures.
According to auth0 the most common types of signatures are
- HMAC + SHA256 Creates a signature using a key and a message. The key is the same every time and the message is the JWT. Common, but more insecure than the asymmetric algorithms below.
- RSASSA-PKCS1-v1_5 + SHA256 Asymmetric signing using RSA. Usually faster than ECDSA.
- ECDSA + P-256 + SHA256 Asymmetric signing using ECDSA. Smaller keys than RSA, resulting in smaller JWTs.
The OpenID Connect Core 1.0 specification defines the ID Token in section 2.
There are a bunch of fields, and following the spec for validating the ID Token is a really good idea. Read the spec. Live the spec.
The ID Token contains claims and typically identifies a user in the context of the OP.
If you are building a service with e.g. Google Sign-In, the ID Token is issued by Google and according to them the RP should use the ID Token to uniquely identify a user in the RPs context (after verifying the integrity of the token).
If you are building your own service and don't have any use for e.g. Google APIs but you still want to use Google accounts for signing in to your service, just use the ID Token and forget about the Access Token.
Typically the access token is a JWT token, but according to the spec it doesn't have to be.
The most important thing is, when you need access to an API (resource), use the token that the authorization server gave you!
Access Token Types
There are a number of access token types.
Whoever presents the token shall be granted access to a resource as long as the token is valid. This is the most common type of access token.
The draft still isn't finalized, but from what I can gather, the token contains some cryptographic content that would make it harder to forge and/or read. A probable use case would be using it in use-cases lacking HTTPS/TLS capabilities.
Don't quote me on that.
A token used to request new access tokens as they expire. Handy if one wants to avoid going through the authorization flow once again.