This is a very specific, technical, pragmatic post. It's just what we enjoy at Infi: getting those important details just right. If you came here for fluffy content about agile, or projects, or fun stuff: better skip this post. You've been warned!
Actually, this is one post in a series:
- The "About" part, describing all moving parts and processes.
- The "Gimme-teh-codez" part, that walks you through the code.
If you already know how the Implicit Flow works, you can safely skip parts of the post. If code says more than words to you, or if you know how Auth0 works, you can safely skip the entire post, and go straight to part 2. For the rest of us, we'll start at the beginning.
About the things involved
We'll start by getting our terminology straight. What's what!?
OAuth2 and OpenID Connect are standards for how to authenticate and (to some degree) authorize users in your systems. It assumes this type of setup with three items:
- An Identity Server application handles user accounts, passwords, 2FA, and all that good jazz.
- Clients (like an Angular application) that send their users to the Id Server to log in, (after which they're redirected back to the Client).
- Your API, which needs the access token on each call to verify access.
This differs from the slightly simpler (but less secure) Resource Owner Password flow. With the Implicit Flow the Client never sees credentials: users trust only the Id Server with those. On the downside, you do have some redirection going on for the user. The user sees login screens from the Id Server, but this should not be a big problem because:
- Either it's a well-known provider, and users are right to trust it.
- Or it's your own identity server, and you can style things to make it "part of the client experience".
Oh, and this flow also quite naturally supports external Identity Providers (the "log in with Google/GitHub/etc" stuff). Which is very nice for users.
Footnote: read more about the Implicit Flow in RFC 6749.
The Identity Server
You can of course create your own Identity Server. Security is hard though, so don't completely roll your own. Instead, use an existing solution to build from.
In this post we won't touch on the API side of things. The beauty of OAuth2 is that the API side of things is largely decoupled from the rest. We will get to the point where access tokens are sent to a dummy API, and assume everything would work from there.
There is one important note about the flow though. Tokens are passed plainly to the API by the client application. The format for such tokens is "JWT" (pronounced like "jot"), typically at least signed (JWS), or alternatively encrypted (JWE). Your API can verify (or decrypt) the tokens.
To do this the API will need to get the public key (or decryption key) from the ID Server. It typically does so "live", by calling the ID Server (cached and refreshed every so often). But you can also provide these keys out of band.
Footnote: read more about JSON Web Tokens (JWT) in RFC 7519.
When a Client determines that a user should log in, it redirects the user to the Identity Server. The user logs in at the Identity Server, and gets redirected back to the Client. The Client at this point expects that the user "brings back" the access token (and possibly id token). This is typically done by the Identity Server redirecting back to the URL of the client with tokens in the hash fragment of the URL.
We will build an Angular CLI application from scratch in part 2 of this series.
In it we will use one of the available libraries for handling the OAuth2 and OpenID Connect parts:
The Angular application will require users to log in with Auth0, and send the retrieved tokens along to the dummy API.
Footnote: read more about Clients in RFC 6749.
Putting things together
Let's put what we learned above in a picture:
The two lines between Client and ID Server in this (simplified!) visualization are "the Flow". They determine how a Client can retrieve a token from the ID Server.
Some specific things missing in the diagram are:
- All log in screens being served by the ID Server. We use Auth0 in this series, so it's all taken care of for us.
- Third party logins, e.g. "Log in with Google". This would include a fourth box all the way to the left, but with Auth0 that only requires configuration, no coding on our part.
- Silent refreshes: access tokens are short lived, so you need to get a fresh one every hour or so. Turns out that's just the normal flow in a hidden iframe, how it works is shown when we work on the code.
And that's all there is to it! In the next part we will start working on the actual code.
Stay tuned for part 2!