The authentication request contains the following in the body (urlencoded format):
- grant_type: constant client_credentials;
- client_assertion_type: constant urn:ietf:params:oauth:client-assertion-type:jwt-bearer;
- assertion_jwt: the JWT signed with the private key held by the client.
This JWT must contain in the header the information on the public key to be used to verify its validity. Furthermore, in the payload, it must contain fixed claims:
- iss: the issuer, that is the clientId of the client that generates the JWT
- sub: the subject, that is the clientId of the client requesting the login
- aud: the identifier of the Client Credentials service
- jti: a unique identifier of the JWT
- iat: the moment of creation of the token
- exp: the expiration date of the token
- client id: the clientId for which the login request is being made;
- token_endpoint_auth_method: constant to private_key_jwt.
Use and validation of the access token
Once the access token has been obtained with one of the two authentication methods supported by Client Credentials, the client can use it to request authorization from the resource owner. This is done by inserting the access token in the request, within the authorization header.
If the requested service is provided by Mia-Platform, the validation is done by the Client Credentials itself.
One of the needs of Mia-Platform customers is to allow external systems to use Client Credentials as an authentication provider and system for assigning permissions. Through this mechanism, an external system will only need to verify the validity of the access token and the permissions contained in the claims.
Let’s see the two mechanisms below.
Validation of the token through Mia-Platform
Once the request has reached Mia-Platform, the access token is extracted from the authorization header.
Client Credentials verifies the validity of the access token through the respective public key and extracts the claims of the JWT. Among these claims there are the permissions that the client has, and which can therefore be used to authorize the client based on the request.
The verification of the permissions, the authorization phase, can be done by Mia-Platform’s Authorization Service. The method by which authorization operations are carried out within Mia-Platform are beyond the scope of this article.
Validation of the token through an external client
As previously mentioned, the access token is a JWT signed using an asymmetric key. Client Credentials exposes a set of public keys (JWKS) through a dedicated endpoint.
An external provider to verify the access token has to:
- get the set of public keys;
- search for the respective public key via a key identifier contained in the access token (in the claim kid contained in the JWT header);
- validate the access token using the public key just obtained.
Once the JWT is validated, the external service extracts and uses the permissions to authorize, or not, access to the requested resource.
The access token has an additional claim, called audience, which contains an identifier of the system that owns the requested resource. When logging in, a client must specify the requested audience.
This claim allows you to avoid improper use of the access token by the recipient, as shown below.
Three systems A, B and C use the same authentication provider and have the following permissions:
- A has permission to access B and C
- B has no permissions to access C
If system A called system B with a token, nothing would prevent system B from using the same token to access system C, which it should not be able to access. Since in the login phase the client A specified B as the audience, therefore the access token can only be used to access B.
Since the audience is saved among the claims of the JWT, an external system can, and must, check if that token has been created to access that specific system.
There are several ways to manage M2M authentication. We have chosen to create a dedicated service, Client Credentials, which uses the Client Credentials flow of OAuth 2.0, and the Client Authentication methods client_secret_basic and private_key_jwt described in OpenID Connect 1.0.
By creating a specific component, in addition to freeing ourselves from third parties, we were able to calibrate the choices on our performance needs – using Go language – and security – by implementing jwt technology.
The result is a new platform component, secure and performing, which can be configured quickly and easily, with significant cost savings.
This article is written by Davide Bianchi, Senior Technical Leader, and Davide Tantillo, Senior Technical Leader.