What is an API?
There is probably a lot of ways to explain this, however my favourite one is from MuleSoft: https://www.mulesoft.com/resources/api/what-is-an-api. There is a nice video – which explains in plain English – what API is, using analogy to a waiter in a restaurant.
The waiter acts as an API – takes orders from consumers (customers in a restaurant) and passes that request to a server (the cook). The cook prepares requested resources (meal) and sends it back to the consumers.
APIs are used to connect services and applications within a company network or over the Internet, allowing them to exchange data and execute actions related to that data. It’s a common pattern nowadays, and when you are interacting with Instagram or Facebook on your phone – you are using their APIs underneath.
There are various types of APIs out there. I recommend MuleSoft’s article again, since I find it quite informative and clear: https://www.mulesoft.com/resources/api/types-of-apis. In this post I will focus on RESTful APIs. I will also assume that the HTTP application level protocol is used to deliver these APIs.
Why to protect an API?
Let’s take that Facebook account. I wouldn’t like someone to use his computer to publish opinions (to say the least) on my profile. For that purpose, I am using my login and password to authenticate with Facebook. Once I have authenticated, that identity is used to communicate with its APIs. The answer to that question then becomes natural – because we value our privacy, money, reputation, etc. – we don’t want others to be in control what should be only ours.
How to protect an API?
In the world of RESTful APIs (over HTTP) one can choose from various “protection” methods. Lets have a quick look at possible authentication schemes that the HTTP protocols offers (source: iana.org):
- and other
I have highlighted Bearer scheme, as OAuth 2.0 is an authorization framework based on Bearer Tokens:
Any party in possession of a bearer token (a “bearer”) can use it to get access to the associated resources (without demonstrating possession of a cryptographic key). To prevent misuse, bearer tokens need to be protected from disclosure in storage and in transport.https://datatracker.ietf.org/doc/html/rfc6750
The current version of the protocol is OAuth 2.0.
We already know that OAuth is based on Bearer tokens. This allows to define flows of the framework that can be applied in various situations or use cases.
The main goal defined by OAuth is to get access to secured data owned by a Resource Owner (or easier – data owner). Because the data is protected, Access Token must be obtained. This Access Token is subsequently used as the Bearer token in the HTTP Bearer authentication scheme.
Resource Owner is a role and it can be a person, a service or by definition “An entity capable of granting access to a protected resource”.
There are other roles defined by the OAuth specification, namely:
- Client – an application or process that makes a request to get data owned by Resource Owner on behalf of the Resource owner
- Authorization Server – the server issuing access tokens to the client after successfully authenticating the resource owner and obtaining authorization
- Resource Server – the server that keeps the data safe, and is capable of decoding access tokens presented by the client
OAuth specification doesn’t define how the Resource Owner is being authenticated, hence it is called Authorization Framework. It introduces a concept of Authorization Grant – in other words – a permission to access requested data by the calling application (Client). This authorization consent might be implemented as HTML form with Allow and Decline buttons, informing the Resource Owner of the access scope requested by the Client. The consent might also be automatic (or implicit) – maybe because the Authorization Server and Client are delivered by the same company.
OpenID Connect is built on top of OAuth and incorporates authentication into the flow.
The following image illustrates general idea behind OAuth flow:
- Resource Owner (a person in this example), using their tablet, is accessing an application (Client) to get their private data from the Resource Server.
- Because data is protected, the Client must first obtain an Access Token from the Authorization Server and present it to the Resource Server. It musts also get permission from the Resource Owner to access their data
- The Authorization Server asks the person for authorization of the request that the client app is going to make on their behalf (authenticating the user is out of scope for OAuth)
- The Resource Owner agrees to grant permission to the Client to make the call
- Authorization Server issues Access Token to the Client, which can be used to authorize requests to the Resource Server
- The Client is using obtained Access Token to request the data from its source
- Resource Server, after validating Access Token and making sure that it contains proper access permissions to the data, sends the data to the Client
- Finally, the Resource Owner can read their data on the screen of their tablet, in the Client application
A Bearer Token is an opaque string, not intended to have any meaning to clients using it. Some servers will issue tokens that are a short string of hexadecimal characters, while others may use structured tokens such as JSON Web Tokens.https://oauth.net/2/bearer-tokens/
Bearer tokens – as you already know – are used by OAuth as ‘passes’ to get protected data or to execute protected operation. These can be structured in any form, however JWTs (JSON Web Tokens) have been widely adopted. There are 2 types of tokens in OAuth: access token and refresh token. The first one we already know, the second is used to generate new access token once the old one has expired. Refresh tokens allow clients to obtain access tokens without asking users for consent, and users don’t have to authenticate again.
Always keep tokens secured:
- store them in a secure manner (e.g. Secure, HttpOnly cookie if the client is web app)
- transfer them using secure protocols (e.g. TLS for HTTP).
There is more to it (see rfc recommendations or auth0 article), but use these two rules as a bare minimum. Another rule of thumb is to issue access tokens only for a short time (shorter than an hour, e.g. 30 minutes), whereas refresh tokens could have a longer expiration time (e.g. 8h).
JWT Tokens (JWTs)
JWTs can be used as OAuth 2.0 Bearer Tokens to encode all relevant parts of an access token into the access token itself instead of having to store them in a database.https://oauth.net/2/jwt/
JSON Web Tokens have their own specification. Since JWTs are JSON structures, the specification defines what fields should this structure contain. There are great guides on the Internet that I recommend reading in order to dive deeper into JWTs:
- JSON Web Token Claims by Auth0
- Introduction to JSON Web Tokens by jwt.io
It is important to understand, that JWT tokens carry information about user’s claims or permissions in its structure. That is why these tokens must be digitally signed by the Authorization Server. Resource Server needs to check that signature by examining JSON Web Keys (JWK) stored on the Authorization Server (see rfc7517).
These are simple, short strings generated by Authorization Server, and the server can decide about their format. In a nutshell, these are IDs that reference a user session on the server, and can be exchanged for user information with the server.
JWT or Opaque?
JWTs are heavier than opaque tokens – keep that in mind when using them in cookies. It can happen that you would have to use more than one cookie to fit the whole token.
Opaque tokens are a lot lighter, however they don’t carry any information about the user, hence additional action to get details about the user is required.
One may argue that you could cache user info on the Resource Server. Thinking about large farms of servers however, used by many users simultaneously, having a cached copy of a public key to check signature on the Resource Server itself, seems like an option to consider.
In this post you have read what OAuth is and how it is related to RESTful APIs. You have seen general authorization flow, OAuth roles and elements in that flow. We have finally touched on OAuth tokens, which are used as bearer tokens – i.e. such, that when presented, prove the identity of their holder.