Spring Security & OAuth 2.0: In-Depth - header image

Spring Security & OAuth 2.0: In-Depth

Last updated on October 17, 2020 -

Who the hell am I?

I'm @MarcoBehler and I share everything I know about making awesome software through my guides, screencasts, talks and courses.

Follow me on Twitter to find out what I'm currently working on.

You can use this guide to get a deep understanding of OAuth 2.0 and how you integrate Spring Security with it.

Intro

As with all other articles on this site, this is not a "5 easy steps to integrate Spring Security and OAuth 2.0", but rather a comprehensive "what, how and why" @ ~7,000 words.

It will save you days, if not weeks, in understanding and setting up Spring Security & OAuth 2.0.

You can read a short preview of this guide at the bottom of this page, or get full instant access here:

Get Instant Access| $X

($X net plus $X VAT)

Changelog

Update 1 - Sep 29, 2020

  • Significantly reworked social login section (Facebook, GitHub), with explanations and code examples

Initial Release - Aug 21st, 2020

  • First Release

  • Containing: Chapters on Spring Security & Authorization Servers, Clients and Resource Servers

Beta 1 — Aug 13th, 2020

  • Initial Beta

  • Containing: OAuth Overview, Flows, (parts on) JWT and JOSE.

Table of Contents

  • Introduction

    • The confusing OAuth 2.0 world

    • What is OAuth 2.0

  • OAuth 2.0 - An Overview

    • Meet: Resources, Owners & Clients

    • Meet: Authorization Servers

    • The Access Token OAuth 2.0 Dance

    • Side-Note: Different OAuth 2.0 Flows

    • How does the protected resource verify access tokens?

    • OpenID - The OAuth 2.0 Social Login Dance

  • Spring Security & OAuth 2.0: Overview

    • A version history

  • Spring Security & OAuth 2.0 Authorization Servers

  • Spring Security & OAuth 2.0 Resource Servers

    • What dependencies do I need to get started with Spring Security and OAuth 2.0 Resource Servers?

    • How do I configure the Resource Server support?

    • What does my resource server code look like?

    • Where can I find out more about Resource Server?

  • Spring Security & OAuth 2.0 Clients

    • What dependencies do I need to get started with Spring Security and OAuth 2.0 Clients?

    • How do I configure the client support to get a fully configured OAuth 2.0 rest client?

    • How do I use the OAuth 2.0 WebClient?

    • How do I protect my application with OAuth 2.0 logins?

    • How do I get access to the (logged in) user’s data?

  • Fin

    • Outro

    • What’s missing in this article

    • Full Source Code

    • Acknowledgments

Preview

Here’s a sneak peek into the article, covering parts of the first chapter OAuth2 - An Overview.

==================START OF PREVIEW=============

Introduction

The confusing OAuth 2.0 world

It seems like almost every company out there is using OAuth (2.0), but understanding what it does or how it works leads to a lot of head-scratching.

You get bombarded with words like Authorization Server, Protected Resource, Client, Access Tokens, Refresh Tokens, different Authorization Flows, grant types, JWT, JOSE, OpenID Connect, social logins and the list seemingly never stops.

Then add Spring Security on top of that, a framework that is already complex enough without OAuth, consisting of different projects, modules and versions supporting different parts of the OAuth universe.

This could easily lead to learned helplessness, so let’s try and bring some light into the OAuth darkness.

What is OAuth 2.0

The short answer:

At its core, OAuth 2.0 is just an authorization framework, granting clients access to protected resources via an authorization server.

Wow, that sentence doesn’t help at all, does it?

Luckily, there’s also a long answer:

The remainder of this document. Note, that whenever I mention OAuth in this article, I’m referring to 2 of the OAuth protocol, i.e. OAuth 2.0.

OAuth 2.0 - An Overview

As always, it helps to start with the basics. It absolutely does not make sense to jump right into Spring Security’s OAuth integration, before having a firm grasp of the OAuth 2.0 basics.

Forget all the social logins (like 'login with GitHub') or whatever you might associate with OAuth, for now, and focus on what the original problem is that it tries to solve.

Imagine you have a bank account (or in this website’s case a Stripe account). Also, imagine, you want to give a 3rd party (limited) access to that bank account.

That 3rd party could be a consumer app which tries to categorize and report on your monthly spendings or, in my case, a web-service that generates PDF invoices for all transactions in my Stripe account.

The problem:

  • You don’t really want to give that 3rd party application your username/password combination to your account.

  • Also, you want to somehow limit what the 3rd party application can do with your account: I.e. allow it to read your banking transactions, but certainly not allow it to create new transactions.

  • You also want to be easily able to revoke that access, i.e. not let the 3rd party access your bank account anymore, whenever you say so. (If they have your credentials, good luck with that.)

In other words, the original problem that OAuth tries to solve in this very specific example:

How can you safely give a 3rd party application limited and revokable access to your bank account?

Unlock Account

Meet: Resources, Owners & Clients

To answer that question, let’s get technical and learn about OAuth’s terminology.

Rephrasing the problem above in OAuth speak looks like this:

How can the resource owner (you) give a client (3rd party software) scoped access (read or write or both) to a protected resource (bank account)?

Let’s break this down.

  • The resource owner is you, the user, who holds the rights to something.

  • That something is called protected resource, i.e. your bank account.

  • The 3rd party application, who wants to access the protected resource in your place, is called the client. Never confuse the client with the resource owner.

  • (Additionally, the client only gets scoped access, i.e. it can only read transactions in this example)

These are three main players of every OAuth interaction, but a fourth one is missing. Who is it?

Meet: Authorization Servers

Let’s have a quick Q&A session.

Q: How does the client (3rd party software) convince the protected resource (bank account) that it is allowed to read the transactions in your bank account?

A: Simple: It needs to show up at the protected resource with a valid access token. For now, if it helps, think of an access token as a physical key card and your bank account as a vault with a printed list of transactions inside.

The client doesn’t care how the key card is built and how it works etc. The client only cares that he has it and it opens up the vault.

Oauth2 Vault

Q: I’ve heard that access tokens are sometimes also called bearer token. Why?

A: Because whoever bears (fancy word for: holds) a (valid) token, gets access to the protected resource. Think back to your key card. Anyone who bears the key card could open your bank account, with no more questions being asked.

Q: Ok ok. Now, where does the client get that access token from?

A: From another involved party, that everyone (you, the client, the protected resource) trusts: the authorization server. Its main job is to hand out those access tokens.

In our banking example, the protected resource (bank account) and authorization server would both be provided by the bank. It could be two different systems, or the same system with two different endpoints.

Q: But then any client can simply go to the authorization server and ask for an access token?

A: Not quite. There’s one piece of information missing. The client only gets an access token from the authorization server, when you, the resource owner, successfully authenticates (think: login) at the authorization server and allows the client to get that access token.

A bit too abstract? In summary: The main goal of the OAuth 2.0 flow is for the client to get a valid access token. How that’s done specifically, we’ll see next.

The Access Token OAuth 2.0 Dance

Meet the (quite elaborate) access token dance. (A big thank you goes out to Andreas Eisele, who drew the flow chart below).

Oauth2 Flow

Getting and using an access token happens in 3 phases and you can see those phases in the flow above depicted by the horizontal, dotted lines.

Let’s break the phases down.

Phase 1 : Getting An Authorization Code

Imagine, you (the resource owner), are logged into the website of that 3rd party application (client) which categorizes your monthly spendings (household, electronics, utilities etc.). Let’s call that 3rd party application MoneyMoneyMoney for now.

There’s a big button:

Oauth2 Add Bank Account

Now what happens when you click that button?

The answer is, you get redirected away from that website, to an authentication endpoint of your bank.

Oauth2 Login Bank

And, upon successful login, the bank asks you if you want to grant MoneyMoneyMoney access to your bank account. It also displays you a list of "rights" that MoneyMoneyMoney is supposed to get.

In this case, it should only be able to access and manage transactions (like tagging them), not create new transactions.

Oauth2 Authorize

If you click Authorize Access, what actually happens is that the authorization server generates a so-called authorization code and redirects you back to MoneyMoneyMoney’s website with that authorization code as a URL parameter.

This could result in the following request back to the client.

https://moneymoneymoney.com/callback?code=89sHBN123nd&state=...

With the authorization code being 89sHBN123nd (and ignoring the other parameters for now).

Now, your job, as the resource owner (user) is done. The client needs to turn that authorization code into an access token, for now.

Phase 2 : Getting An Access Token

This phase is essential, but happens entirely in the background. Hence, there are no fancy screenshots.

Upon receiving the authorization code, the client needs to turn it into an access token. This happens through a separate HTTP call to the authorization server, but there’s a tiny catch.

The client needs to present the authorization code and client credentials in that HTTP call.

Where do these client credentials come from?

At some point, before being able to do this whole OAuth dance, every client must register with an authorization server, so that the authorization server actually knows the client. In this process, the client gets its credentials.

So, if you are the developer of the MoneyMoneyMoney application, you would try to get a developer account at the bank and create a new OAuth application through its website.

Oauth2 Registration

This is the form that you’ll likely have to submit. The most important part is the callback URL, i.e. the URL from your application that the authorization server needs to call with the authorization code.

Oauth2 Credentials

Upon successful registration, you will get a set of credentials. Which you can use to convert the authorization code into an access token.

(Note: More advanced readers might already know that, additionally, there is a process of dynamic client registration, but we will skip this for now and keep things static & simple).

The access token is returned as a JSON object and could look like this:

{
    "access_token": "lkjl5qwek516nbleearrgh",
    "token_type": "Bearer"
}

The interesting part is now this: Contrary to popular belief, there is no pre-defined format for <access tokens>, they can literally be any string, from "lkjl5qwek516nbleearrgh" to a Base64 encoded JSON Object (like the popular JWT - more on that in a bit). Some people might even use a wrongly indented Kubernetes YAML descriptor as access token ;).

Also: The client doesn’t care, nor know, nor understand what the access token it gets back is. It only needs to store it somewhere and then use it whenever it wants to get access to the bank account.

Phase 3: Using The Access Token

==================END OF PREVIEW=============

If you’d like to continue reading, get instant full access here:

Get Instant Access| $X

($X net plus $X VAT)

Share:

Comments