In this article we will talk about how to manage machine to machine (M2M) authentication through the OAuth 2.0 authorization protocol. We will try to shed some light on the differences among authorization, authentication and the authorization delegation mechanism. We will refer to the OpenID Connect 1.0 (OIDC) specification from which we took inspiration for the implementation of authentication methods.
In the next article instead, we will illustrate and describe our implementation of the M2M authentication and authorization mechanism through the Client Credentials component.
Sooner or later you need to expose data via APIs and you need to make data available for consumption only to designated customers.
Several projects come into play such as login, credentials, tokens, permissions, authorization, authentication, the flow and order in which certain actions must be performed, and so on. Each of these actions has a precise meaning and boundary. So let's try to clarify a bit.
Authentication and Authorization: what are the differences?
First we explain the difference between authentication and authorization, two terms often used interchangeably, but which actually have two different meanings and functions.
Authentication allows you to verify that the caller is who he claims to be and therefore to verify his identity. This operation is done through the validation of credentials which can be passwords, biometric data, digital signatures and other methods based on the level of security required by the system. Authentication is usually performed before authorization.
Once the user is authenticated, the authorization establishes the resources they can access by assigning user permissions, rules and policies.
Summing up, authentication allows you to verify the identity of the caller, while authorization allows you to determine the resources that the caller can or cannot access.
It is not easy to manage authorization and authentication. Especially if the server that wants to access a third party resource is a different server than the one that owns it.
Fortunately, there are protocols that help you choose and implement the correct flow for your use case. The best known is the OAuth 2.0 protocol which we will discuss below. We will see that OAuth 2.0 is not an exhaustive specification on authentication and authorization mechanisms, but it deals with describing multiple mechanisms for obtaining an authorization token.
RFC 6749: The OAuth 2.0 Authorization Framework
OAuth 2.0 (OAuth) is described in the RFC 6749 specification titled “The OAuth 2.0 Authorization Framework”. On the oauth.net website it is introduced as “OAuth 2.0 is the industry-standard protocol for authorization”. By reading these contents you might think that this protocol strictly deals with authorization. Nevertheless, OAuth implies that the system that applies the authorization policies and that grants access to resources already exists.
So what does OAuth 2.0 do?
This protocol can be better framed if described as an access delegation protocol. The role of OAuth is to describe how a client can access the protected resources (Resource) of a user (Resource Owner), which reside on a third server (Resource Server), without the client being aware of the Resource Owner’s credentials.
Figure 1: Abstract protocol flow
The mechanism, as described by the theoretical flow of the protocol that you can see in figure 1, works through the following steps:
- The Resource Owner gives the Authorization Grant to the client [Steps A, B];
- The client gets an Access Token, with which he can access the protected resource [Steps C, D];
- The client uses the Access Token to access the protected resource [Steps E, F].
Before providing further explanations, it is necessary to make a couple of clarifications.
As a keen eye might have already noticed from the first lines of this paragraph, OAuth does not deal with authentication, at most it gives some suggestions. Nor is OAuth an exhaustive guide on how to implement authorization mechanisms within your system; rather it is a specification that describes the sequence of actions that must be done (MUST), those that should be done (SHOULD), those that can be done (MAY) and those that must not be done (MUST NOT). How these actions can be implemented is beyond the scope of this protocol, although it often provides some hints about it.
For example, in section 3.1 Authorization Endpoint of the specification, you can read:
"The authorization endpoint is used to interact with the resource owner and obtain an authorization grant. The authorization server MUST first verify the identity of the resource owner. The way in which the authorization server authenticates the resource owner (e.g., username and password login, session cookies) is beyond the scope of this specification."
The specification therefore requires that to use the authorization endpoint, the Authorization Server must verify - authenticate - the identity of the Resource Owner, but does not describe how.
This is just one example of other circumstances where the OAuth 2.0 specification leaves freedom of implementation. This freedom is often not appreciated by developers, who don’t know how to implement the aspects that the specification does not define. In addition, another risk is also to make an implementation that does not comply with certain safety requirements.
For this reason we often rely on external services (Okta, Auth0, Authlete) that implement the protocols mentioned above while respecting the necessary security requirements and offering multiple implementation alternatives, such as different authentication methods.
So the main purpose of the OAuth 2.0 specification is to define:
- How the client obtains the Access Token;
- How the client can use the Access Token to get access to the requested resource.
The most interesting part of this protocol is precisely the flow to obtain the token. Let's see how it can happen.
Authorization flows (Grant Type)
The OAuth 2.0 protocol describes four possible authorization flows and each of them has a particular use case.
- Authorization Code Grant: used by server side applications.
- Implicit Grant: used by mobile or web applications (SPA), or by any other applications that run on the user's device (User Agent). In this flow, the Access Token is passed on to the User Agent, potentially making the Access Token accessible to unauthorized parties. Its use is not recommended and where possible you should use the Authorization Code Grant with Proof Key for Code Exchange (PKCE), which is an extension of the Authorization Code Grant and described in a separate specification (RFC 7636).
- Resource Owner Password Credentials Grant: used by applications considered highly secure (trusted) since the user's credentials pass through the application itself. It is typically used in legacy or migration applications. The specification itself says in paragraph 10.7 that it is an anti-pattern compared to what the protocol itself tries to avoid: the user must grant his credentials to the client who will impersonate him.
- Client Credentials Grant: used for API access through M2M interaction.
The detailed explanation of each of these flows is beyond the scope of this article; on the internet there are many resources that explain in detail the flows mentioned above (1, 2, 3).
We will focus exclusively on the last authorization flow, the Client Credentials Grant.
Client Credentials Grant
Client Credentials Grant is certainly the simplest of the OAuth 2.0 authorization flows. It can be guessed from the following graphic representation:
Figure 2: Client Credential Grant Flow
As shown in Figure 2, this flow does not involve interaction with a user, nor with a user's device: the client is a server - therefore a machine - and must access a resource on a Resource Server, another machine. This is exactly the hypothesis we illustrated at the beginning of the article: the consumption of an API through a M2M interaction.
The OAuth 2.0 specification (4.4 Client Credentials Grant) states:
"The client can request an access token using only its client credentials (or other supported means of authentication) when the client is requesting access to the protected resources under its control, or those of another resource owner that have been previously arranged with the authorization server (the method of which is beyond the scope of this specification). The client credentials grant type MUST only be used by confidential clients. "
As we have already seen, OAuth does not deal with authentication and the specification simply states that client credentials or other supported means of authentication are sufficient to obtain the Access Token.
This method is used when the client requests access to:
- Resources that belong to him (the client is the resource owner himself);
- Resources that belong to another resource owner who has previously agreed with the Authorization Server to give client access to the resources. This mechanism is not defined in the specification.
Lastly, the RFC explains the input and output format of the Access Token request.
At this point it may seem that the Client Credential flow is so trivial as to be useless to implement it, so you might consider to implement your own mechanism without adhering to these specifications. Its strength lies precisely in its simplicity: OAuth 2.0 standardizes the authorization flow with which an API can be used in a M2M interaction.
In a M2M dialogue, Mia-Platform - thanks to a specially developed microservice - offers the ability to access its APIs through the standard OAuth 2.0 Client Credentials mechanism, making integration as simple and fast as possible.
Client authentication in OpenID Connect 1.0
OpenID Connect 1.0 is a mechanism built on top of OAuth 2.0 that standardizes user identification. It arises from the need to reduce the effort involved in integrating with the Identity Provider to authenticate a user and obtain additional information about it.
In the past, each Identity Provider used to give permissions and to build custom APIs on OAuth 2.0, which were dedicated to obtaining identification information on a user. Consequently, a client, in order to make various authentication / identification providers available to users - the classic logins with Google, Facebook, LinkedIn, etc - had to implement different mechanisms for each of them.
OIDC 1.0 standardizes these mechanisms by providing tools such as the ID Token, the /userinfo API and standard names for various identification properties (name is given_name, surname is family_name, full name is name, etc.) drastically reducing time for integration with the Identity Provider.
All this has enormous value where there is a user, but the interaction described in this article is between two machines. Why do we talk about it then?
As mentioned earlier, OAuth 2.0 remains quite vague about how the client can authenticate with the Authentication Server.
In paragraph 2.3 Client Authentication of RFC 6749 it is in fact stated “The authorization server MAY accept any form of client authentication meeting its security requirements”, leaving freedom of implementation for the Client Authentication. OIDC not only standardizes user identification, but defines some simple and secure ways to perform the Client Authentication.
In Mia-Platform we have implemented within the Client Credentials component the client registration, the OAuth 2.0 Client Credentials flow and the client_secret_basic and private_key_jwt Client Authentication methods described in OpenID Connect 1.0.
In the next article we will describe how these specifications have been implemented, showing how an external client can access an API provided by Mia-Platform or by a third party service, using Mia-Platform as the authentication and authorization provider.