I currently have an API proxy for generating and revoking OAuth2 access tokens.
In this proxy, there are flows for each operation (Generation, Revocation and Refresh).
I created a policy for generating access_token using client_credentials grant type, a policy for revoking access_token and a policy for refreshing access_token, each applied to the request field of each flow.
The problem I'm having is that when I do a request to the endpoint of the flow responsible for generating access_token (/oauth2/access_token), I only get the access_token. According to Apigee documentation, client_credentials can't generate refresh_token alongside the access_token.
The other problem is that the body of my "Refresh Access Token" policy doesn't return anything, even though I enabled the "GenerateResponse" option.
In my organization, we need to authenticate the client application without using a password and being able to extend the lifespan of the access_token without the user re-authenticating.
How should I proceed?
The problem I'm having is that when I do a request to the endpoint of the flow responsible for generating access_token (/oauth2/access_token), I only get the access_token. According to Apigee documentation, client_credentials can't generate refresh_token alongside the access_token.
That is correct. The reason for that is the refresh token in this case would be useless.
IETF RFC 6749 is the relevant standard here, specifically section 6 of that standard . It states that when refreshing an access token, "The authorization server MUST require client authentication for confidential clients or for any client that was issued client credentials".
In other words, according to the standard, when refreshing a token, the client must pass its credentials. Therefore there is no advantage to enabling the "refresh token" grant type for a token that was originally granted via client credentials grant type (or its equivalent). It's simpler to just request a new token, in the same way your client requested the original token.
Given that, I advise you to abandon the idea of implementing a refresh flow for a token that was originally generated via client_credentials. Refresh flow makes sense to refresh a token that authenticates a USER; the refresh flow allows the authorization server (Apigee in this case) to skip the user authentication step, which makes for a cleaner user experience, while still preserving the security benefits of a time-limited access token. But it doesn't offer any advantage when there is no user that has been authenticated. To get a new token, just send the request for a token, via client_credentials grant, again.
Remember, a client_credentials grant type is there to authenticate ONLY the client. It's typically used in system-to-system interactions, when one headless system makes a request to another system. There is no user present.
In my organization, we need to authenticate the client application without using a password and being able to extend the lifespan of the access_token without the user re-authenticating.
Using client_credentials grant type, you are not authenticating any user. The client credentials grant type authenticates the client (the app). It does not authenticate the user. There is no user.
You are correct that the refresh token grant type is intended to allow refreshing of an access token without requiring any additional interaction by the user. But this is relevant only when there is a user involved; in other words, only when the original token was granted via an authorization_code grant type, or possibly a password grant type. In either of those cases, Apigee will issue a refresh token, and you will be able to implement the refresh grant type. (But again, in the refresh flow, the client MUST authenticate!)
Finally, you used the word "password". Clients don't have passwords. They have credentials, often a client id and secret, but not always. An alternative might be a private RSA key, for example. But in any case, we don't call them passwords. The id+secret pair may LOOK LIKE a username+password pair, and often it works like a username+password pair. But it's not the same. The password needs to be keyed in by a user; eliminating that step is the goal of a refresh grant type. The client secret is not keyed in by a user. It's stored in client application code. There is no user interaction required, to allow a client application to transmit its credentials to the token dispensary. Therefore the refresh token grant type offers no utility in the case of a token granted via client credentials grant type.
I hope this is clear!