10/31/2017

A Quick Look at OAuth2

TLDR;

If you need to access OAuth 2.0 protected resources, than go ahead and use the official SDK from your OAuth 2.0 provider, if available.

If you want to implement the server-side you might want to reconsider, as OAuth2 is both complicated and doesn’t do what you need on it’s own.

Background & Goals

Recently I’ve taken a look at OAuth2, to find out if it’s a good fit for projects I am working on. To be specific, I was wondering if I should implement it as my means of Authentication.

I was looking for a framework that:

  1. should be simple to understand / straightforward to implement
  2. should allow my app to receive basic information about the user
  3. should allow my server to deliver content based on the users identity

In this article I present why I don’t think that OAuth 2.0 meets those requirements. Should your requirements look like mine, then I suggest you rethink if you really want to use OAuth 2.0.

Disclaimer: Every use case is different - so if you find that it still makes sense to deploy OAuth 2.0 in your system then don’t feel discouraged to do so!

Note: If you are only interested in accessing OAuth 2.0 protected content from another service provider - that is if you are only implementing the client, then you have no choice anyway and can go ahead!

First let’s take a look and what OAuth 2.0 is and who is using it.

So let’s get started!

What is OAuth 2.0?

The short version:
OAuth 2.0 is a delegated authorization framework for the enterprise.

For the long version, you can read all about OAuth 2.0 in it’s 70+ pages rfc 6749.
It also has a dedicated homepage at https://oauth.net/2 and a wikipedia page.

When talking about resources to read about OAuth 2.0, I think it’s worth mentioning that the lead author Eran Hammer was unhappy about the path that it has taken and resigned and had his name removed from the project. You can read up on his reasons for doing so on his blog.

Also we will find out that there are 2 additional RFCs that you may need to get familiar with,

Who is using it?

If you are going to use a technology, it doesn’t hurt to take a look at who is also using it. In this case, it’s the big players:

  • Amazon
  • Facebook
  • Google
  • Microsoft
  • Twitter

If you want to take a look yourself, here is a wikipedia page that lists a number of known OAuth service providers. But not all of them implement 2.0 - many are still using 1.0 and 1.0a.

On one hand this looks rather promising, as a lot of big companies have embraced OAuth 2.0. On the other hand quite a few decided to not upgrade from an older implementation like 1.0 to the newer 2.0 version, even though Version 2.0 was published in October 2012.

How does it work?

At it’s heart, OAuth 2.0 specifies a flow that defines:

  • which party is calling which party
  • in what order those calls are made
  • and what is the data that is being exchanged

To understand it, you need to learn it’s terminology and learn about the specific flows it supports. The flows take advantange of the terminology, so you need to understand the terminology first - that’s why I’ll start with those.

OAuth 2.0 Terminology

To make sense of it, you’ll need to learn it’s terminology.

Involved Parties

First you need to know about the involved parties:

Client
A client application, e.g. your web-, mobile- or desktop-app.
Resource Owner
The user of your app who also happens to have access to some content on an OAuth 2.0 protected server.
Resource Server
An OAuth 2.0 protected server that serves some content if you hand it a valid Access Token.
Authorization Server
A server that the Resource Server trusts. It hosts a login page, that the user logs into. After the user logs in successfully and confirms the request, it will issue an Authorization Grant. It will also exchange an Authorization Grant for an Access Token for the client.

Exchanged Objects

Then you need to know about the objects being being exchanged between those parties:

Resource
A Resource is some user content protected by OAuth 2.0 and provided by a Resource Server.
Authorization Request
The Authorization Request is what happens when your App requests access to a Resource of the User.
Authorization Grant
The Authorizaton Grant is returned as a response on a Client’s successful Authorization Request. It can be exchanged for an Access Token.
Access Token
A token that is used to retrieve content from a Resource Server instead of user credentials. It is issued by the Authorization Server.
Refresh Token
An optional token that can be returned by the Authorization Server in addition to the Access Token. It can be used to retrieve additional Access Token if for example the original Access Token expires.

Authorization Grant Types

Then there are different Authorization Grant Types and the choice of the Grant Type influences how the Access Token can be obtained. There are four base Authorization Grant Types specified in OAuth 2.0:

  1. Authorization Code
  2. Implicit
  3. Resource Owner Password Credentials
  4. Client Credentials

The specifics are not terribly important at the moment - you may want to skim them, as I will call out the differences between them later on. The first one, Authorizaton Code, is the most important one as we will see.

Authorization Code

This is the classic OAuth flow.

  1. The Client redirects the Resource Owner to the Authentication Server.
  2. The Client logs in, confirms the requested access rights.
  3. The Authentication Server redirects back to the Client.
  4. The Client exchanges the Authorization Code to the Access Token by calling the Authentication Server.

Note: This is the preferred Authorization Grant Type.

Implicit
  1. The Client redirects the Resource Owner to the Authentication Server.
  2. The Client logs in, confirms the requested access rights.
  3. The Authentication Server responds directly with the Access Token.
Resource Owner Password Credentials
  1. The Client asks the user for username and password.
  2. The Client sends the username and password to the Authentication Server.
  3. The Authorization Server responds with the Access Token.
Client Credentials
  1. The Client sends his own username and password to the Authentication Server.
  2. The Authorization Server responds with the Access Token.

OAuth 2.0 Flow

An OAuth flow lists the number and order of steps that are executed between the involved parties. The specific steps depend on the authorization grant type being used.

Let’s start with a simple case, as shown in the abstract protocol flow that is also sketched out in the RFC. It can be visualized in a sequence diagram like this:

OAuth2 Protocol Flow
OAuth2 Protocol Flow

This flow would be used if the Authorization Grant Type Resource Owner Password Credentials is used - that’s why the Client would ask the Resource Owner directly.

This flow, although simple, is not the recommended approach. In this flow the Authorization Request is sent directly to the Resource Owner, but in the recommended approach the Client should send it to the Authorization Server as an intermediary for enhanced security of the user credentials.

The preferred flow uses the Authorization Grant Type Authorization Code and looks like that:

OAuth2 Preferred Protocol Flow
OAuth2 Preferred Protocol Flow

But wait, that’s not all - the previous sequence diagramm was still missing the flow for using Refresh Tokens. So here we go with Refresh Tokens added to the mix:

OAuth 2 Refresh Token Flow
OAuth 2 Refresh Token Flow

Now we know a little about how the flow looks like, let’s take a closer look at one of the objects that is central to the flow, namely the Access Token.

What are Access Tokens made of?

If you expect that the spec defines how the Access Token should look like, you will be disappointed, because the Access Token is defined only very vaguely as a string.

The RFC does not get any more specific than that - quite the opposite, it states that Access Tokens can have different formats and that those are outside the scope of this RFC but it links to another RFC for further reading.

Bearer Tokens

To get to know more about them you need to read the RFC6750 (The OAuth 2.0 Authorization Framework: Bearer Token Usage) which specifies how the Tokens should be used to access the Resource Server.

Even though RFC6750 specifies how Bearer Tokens are to be used, it does not tell us how a reasonable Access Token should be implemented.

JWT - JSON Web Token

This is were JSON Web Tokens come in!

In yet another RFC7519 we learn about an implementation of an Access Token that can be used in OAuth 2.0, called JWT (JSON Web Token).

JWTs are a topic on their own and discussing them in detail is out of scope of this article.

Their main characteristics are:

  • they hold certain predefined parameters
  • they are extensible with custom parameters
  • they can be signed and/or encrypted
  • they can be serialized to a string

Those properties make them a perfect fit for Access Tokens. In addition to that, those properties allow them to be self-contained. That means they can contain all necessary information for the Resource Server to verify if the Resource Request of the Client is valid and should be served - the Resource Server doesn’t need to call the Authentication Server or look up additional information.

Now we know enough about what OAuth 2.0 is and how it can be implemented.

Is OAuth 2.0 simple to understand?

To come back to the first question I posed at the beginning: Is it simple to understand and simple to implement?

Well, when I started reading up on OAuth 2.0 I didn’t find a nice succinct writeup on the internet for how it works and what it does.

Now after having read through a few resources, I feel like I know why - because it’s complicated.

Basically, you would have to read, understand and implement at least those three RFCs.

So I would answer that question with: No, I don’t think so.

But that’s not all, IMHO it’s also missing some basic features…

OAuth 2.0 is missing Authentication

When you start reading about OAuth 2.0 you soon will find out that the “Auth” part of it’s name stands for Authorization (and not Authentication) as made clear by both the homepage’s first sentence:

“OAuth 2.0 is the industry-standard protocol for authorization.”

I don’t know if I agree with the first part of the sentence, but the “for authorization” part is spot on.

And the rfc’s header:

“The OAuth 2.0 Authorization Framework”

Authorization vs. Authentication

But why the hair splitting, what’s the difference between Authentication and Authorization?

According to Stackoverflow:

Authentication is the process of ascertaining that somebody really is who he claims to be.
Authorization refers to rules that determine who is allowed to do what. E.g. Adam may be authorized to create and delete databases, while Usama is only authorised to read.

or:

Authentication = login + password (who you are) Authorization = permissions (what you are allowed to do)

OAuth 2.0 doesn’t solve the problem of Authentication, only the problem of Authorization.

That’s too bad, because getting some base info about a user is almost always a requirement for an application. At least you want to show the user as signed in and you want to have some basic info that you can display, like a username, so that the user knows under which account he is signed in.

When I started looking at OAuth 2.0, I was under the assumption that it would provide a solution for this very common problem.

But with a vanilla OAuth 2.0 implementation you are out of luck if you expect that it provides a standard way of handling user profile information.

Because those misconceptions are a widely held belief, there is a nice article on the official site that explains common pitfalls.

In OAuth, the token is designed to be opaque to the client, but in the context of a user authentication, the client needs to be able to derive some information from the token.

This torpedoes my goal that I want my app to receive basic information about the user.

On the other hand, the server that is serving the protected content has the same problem as the provided Access Token is not inherently linked to a specific user. Therefore the Resource Server has no idea which user has originated the request.

Or to quote the article once more:

The protected resource is not generally going to be in a position to tell if the user is still present by the token alone, since by the very nature and design of the OAuth protocol the user will not be available on the connection between the client and protected resource.

Which means that my last goal - that the server should be able to provide info based on the users identity - also doesn’t work out of the box.

Solving the User Information Problem

We can of course solve the problem and add the support for the missing features. One option that comes to mind is:

  • Add a User Info Token
  • Host a User Info Endpoint

Adding a User Info Token

One workaround to provide that information, would be extending the Access Token Response.

If you take a look at the example of a complete Access Token Response as specified in th RFC:

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{
  "access_token":"2YotnFZFEjr1zCsicMWpAA",
  "token_type":"example",
  "expires_in":3600,
  "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
  "example_parameter":"example_value"
}

You can see that additional parameters, like example_parameter can be part of the response. This is specifically supported by the spec by requiring that clients must ignore unrecognized response parameters.

So we are free to add an additional parameter. For example we could add a parameter and set it’s value to another serialized JWT that holds the users profile information. Let’s call this additional token User Profile Token.

The response could then look like this:

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{
  "access_token":"2YotnFZFEjr1zCsicMWpAA",
  "token_type":"example",
  "expires_in":3600,
  "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
  "user_profile_token":"..."
}

Now a Client Application is handed profile information of the user in addition to an Access Token and can mirror that information back to the user of the app.

Host a User Info Endpoint

Additionally we could implement a Resource Server that answers a request containing a valid Access Token with our new User Profile Token.

That way, should the User Info returned when retrieving an Access Token have gone stale and is not up to date anymore, a new info can be retrieved.

Open ID Connect

But if that’s such a common use case, wouldn’t it be great if the approach of using a second token and additionally supplying a Resource Server that works as a User Info Endpoint would also be part of a standard?!

That’s why a similiar approach is already standardized in yet another spec called Open ID Connect. Therefore Open ID Connect is basically an authentication layer on top of OAuth 2.0.

So before going down the custom route, it may make more sense to implement Open ID Connect instead - but either way, it’s not part of OAuth 2.0.

In the end having no support for Authentication out of the box is a solvable, although annoying problem.

Use Cases

Now we know what OAuth 2.0 can’t do, what about actual use cases? Let’s go through some usage scenarios based on different application types.

Previously, I’ve talked about the different Authorization Grant Types and looked at abstract flows. Now I want to map them to typical application types that I often implement:

  1. Web App
  2. Mobile App
  3. Desktop App
  4. Console App
  5. Privileged Service

Web App

Consider building a Web App that wants to access a Resource on an Http Server that is protected via OAuth 2.0.

That’s the flow for which OAuth 2.0 was made!

Authorization Code Flow
Authorization Code Flow

In this diagram I’ve modelled the authorization code flow including the browser, because there are two important things going on:

  1. The Web App initiates the loading of the Authentication Server’s login page and cannot get a hold of the credentials of the user. It only receives the Authorization Code.
    That’s especially nice in case of third party apps as you wouldn’t trust them with your users login and password.

  2. The Web App’s Backend server exchanges the Authorization Code against the Access Token. Therefore the Browser (and also the User) does not get a hold of the Access Token.

That’s also nice, because the token is not exposed in an internet cafe or on an unlocked laptop.

Mobile App

Consider building a mobile app that wants to access a Resource on a Http Server that is protected via OAuth 2.0.

There are basically two options:

  1. Either use a WebView to load the login page of the Authentication Server inside of the app and therefore follow the Implicit Code Flow.
Implicit Flow
Implicit Flow
  1. Or ask the User directly for his username and password and follow the Resource Owner Password Credentials flow.
Resource Owner Password Credentials Flow
Resource Owner Password Credentials Flow

Both of these approaches are problematic. In the second case, it’s clear that the user credentials are exposed to the app, but even the first case is also dangerous, because:

  1. Instead of using a WebView the app could simply spoof the login page, as the user can’t be sure that he is inside a sandboxed browser.

  2. Even if the Application is trustworthy and uses a WebView and really loads your login page, you are training your users to put trust in your login ui even if they cannot validate the origin. Which in turn increases the likelyhood of them falling for phishing attacks later on.

Desktop App

As far as accessing OAuth 2.0 protected resources, building a desktop app is very similiar to a mobile app.

You can either use the Implicit Flow or the Resource Owner Password Credential Flow.

The main difference is that WebViews are usually more cumbersome to implement, so it’s way easier to go for the Resource Owner Password Credential Flow.

Console App

If you are building a console app you will be unable to redirect to the Authentication Server’s login page, therefore you will need ask the user for his or her username and password and follow the Resource Owner Password Credentials flow.

Privileged Service

When you are developing a privileged service that runs without user interaction you would implement the Client Credentials flow.

For example you could create a Resource Owner for the Service and provide the credentials in a configuration file.

Summary

In all but the third party Web App scenario OAuth still depends trusting the Application to do the right thing. Either to not spoof the login screen or to handle the user credentials carefully.

Implementations

I am not going to go into much detail about specific implementations as there are many different options and they depend on usage scenario and language preferences. Instead I’ll give only some general recommendations for picking a client library based on what I’ve found.

Because there a lot of different flavours of OAuth, you probably can’t reuse the same client library for all providers.

So if you need to integrate with a specific OAuth Provider, probably the best option is to first check if there is an official client library or SDK for your favourite programming language available that already wraps the OAuth calls.

An additional advantage of that approach is that you get all the other capabilities of their API wrapped as well.

For example Facebook provides an official PHP based SDK.

Using Unofficial Client SDKs

If there is no SDK available for your favourite programming language, the next best thing is probably an unofficial opensource SDK for a specific OAuth Provider.

Using OAuth Client Libraries

In case you want to integrate with multiple OAuth Providers, you could also take a look at client libraries that support multiple OAuth Providers. As they are focused on the multiple providers, they usually handle only the OAuth part, so you still have to handle the provider specific resource requests yourself.

An example is the OAuth2 client library for C#. You can see that to support all those different providers a custom implementation is used for each.

As an alternative you can write the OAuth calls yourself, but you are probably saving time by not reinventing the wheel.

Server Libraries

First of, there is no “default” or “goto” implementation of OAuth 2.0. The reason being that the different companies that are part of the OAuth 2.0 working group wouldn’t agree on one. Everyone wants their language and implementation to be the “correct” one.

If you are looking for general purpose client or server OAuth libraries, a good place to start is the official OAuth 2.0 Website’s list of libraries.

Conclusion

If you are developing a Client Web Application that wants to access Resources that are protected by a third party OAuth 2.0 provider you will have to implement the client side of OAuth, but with a matching SDK that’s rather straightforward.

Things look different on the server-side, as there are a couple of problems with OAuth 2.0 - for me the following are the most pressing:

  • Too complicated for what it does, you need to implement at least three RFCs
  • Missing basic functionality for common scenarios like Authentication
  • Limited usefulness outside of specific scenarios like third party Web Apps
  • Extensibility and vagueness cause differences in implementation

All of the above make me wary of implementing OAuth 2.0 server-side and my advise is to stay away unless you have very specific reasons not to.

What might those reasons be?

  • You are working in an enterprise environment
  • You expect lots of custom built apps
  • Many of them are WebApp
  • You plan to implement Open ID Connect
  • You are willing to spent more time and money than is strictly necessary to solve the problem

If that’s not you, than you are probably better off skipping OAuth 2.0.

References

Last updated 10/31/2017 09:38:09
blog comments powered by Disqus
Questions?
Ask Martin