We are constructing an API and plan to make it available to our customers, who will access it using Bearer tokens. Our customers will connect to our API from server-side code (no client-side apps such as SPAs will consume this API). That is to say, 1) their machines will talk to our machines and 2) the client machines are absolutely trusted.
We looked at two options:
- The Client_credentials grant, which is allowable because the customers’ machines can be trusted with the client_secret. However, we need to know which client is calling our API, and a Bearer token obtained via a client_credentials grant cannot convey identity. Therefore this approach would require a separate Auth0 Client for each of our customers. But is seems clunky and difficult to manage one client per customer. What if we have many clients? On option would be to include a custom header in each request that identifies the customer, but again that seems clunky.
- Use the Resource Owner Password Credentials Grant. Create a user account for each customer. When we set up a customer, give them the username and password that we’ve created for them and make the passwords to those accounts never expire. When they need to call the API, their server-side code will use the Resource Owner Password Credentials Grant to obtain a token, which we can parse to know which customer is calling our API. This blurs the line between “user account” and “machine account”, but really is that a bad thing?
I’m leaning towards option 2. Does this approach seem feasible?
That’s a tough one, not because there’s not a known answer to it, but mostly because both options have enough similarities to turn this into a discussion revolving around personal opinions and which characteristics you consider more important.
For a scenario where a machine is talking to another machine and the machine receiving the requests wants to authorize them based on bearer access tokens issued through an OAuth 2.0 flow then client credentials is the way to go about this. The reason being it’s the grant type included precisely for this scenario as all the other grants imply the presence of an end-user.
Having said that you can reduce client credentials (CC) grant and resource owner password credentials (ROPC) grant into something very similar if you focus on the credentials part. In particular, if the CC implementation uses credentials based on client identifier and client secret which can be seen as equivalent to a username and password. This can indeed make things gray if you’re looking for an excuse to not use client credentials and to be honest the current offering of client credentials may entice you to do that because using client credentials for the use case at hand would fall under the machine to machine auth feature which is currently an enterprise addon only.
In conclusion, the right feature for that scenario is client credentials and the offering in the Auth0 service would give some additional functionalities like the ability to map different API scopes to the clients assigned to each customer which would allow to easily control access to the API at a more granular level per customer. Having said that you may find some of its characteristics less than desirable and consider ROPC as an escape plan which may functionally be feasible in some situations, however, you should be aware that you’re now technically not using the recommended solution and that you’re now responsible for not forgetting about any detail that would lead to issues down the line (aka ROPC for machine to machine scenarios is not supported).