We recently built out an endpoint in our API to allow a user to supply a refresh token and retrieve a new refresh token, using a request from our services as described here.
When testing on our local machines, this flow was able to be successfully executed (a user could supply an expired bearer token + their refresh token and was issued a new bearer + refresh token), but when we deployed endpoint to our staging environment, our call from our services to the Okta <env uri>/oauth2/default/v1/token endpoint was given a 401 response.
Token rotation is enabled, and the scope grant type we are requesting in the request params is refresh_token . The scopes we are requesting are offline_access and openid.
What would be a potential reason behind this? Is the request detailed in the linked article not intended to be made to the Okta API from a backend service, and rather made by our user?
When running this locally, the request completes successfully without an Authorization header, but not the case on our staging environment. I am assuming an expired authorization token cannot be passed as the Authorization header. We will add this and attempt it on our staging environment and see if it makes a difference.
Our use case is that a user on a mobile app has had their authorization token expire, and is attempting to use their refresh token to acquire a new one via our endpoint to avoid going through a login flow. If what we’re attempting isn’t the proper way to go about this, I would be more than open to alternatives!
Just tried using the user’s bearer token to make that request in the Authorization header and got a 401 back from Okta when doing so; this was done on our local instance.
I don’t believe the local application would be appending the request automatically - the code of our request is below:
NewTokenResponse response = webClientBuilder
.baseUrl("https://<our okta domain>.okta.com/oauth2/default/v1/token")
.defaultHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_FORM)
.build()
.post()
.uri(uriBuilder -> uriBuilder
.queryParam("grant_type", GRANT_TYPE_VALUE) // grant type is "refresh_token"
.queryParam("refresh_token", refreshToken)
.queryParam("scope", SCOPE_VALUE) // scopes are "offline_access openid"
.queryParam("client_id", clientId)
.build())
.retrieve()
.bodyToMono(NewTokenResponse.class)
.block();
How would one go about checking if the local version of the application is inserting a header of some kind?
We got our problem solved - turns out the clientId in the yml for our staging environment didn’t match the one we were using on our local environment. The clientId on local was for a native app, and the clientId on our staging was for a Web app.
For posterity: we found the oidc docs to be very helpful; they offered more details about what parameters are needed in which requests (hence why ours were working without a redirect uri nor authorization header)