Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Not possible to force refresh stored access token #43799

Open
AJO35813 opened this issue Oct 10, 2024 · 3 comments
Open

Not possible to force refresh stored access token #43799

AJO35813 opened this issue Oct 10, 2024 · 3 comments
Labels
area/oidc kind/enhancement New feature or request

Comments

@AJO35813
Copy link

AJO35813 commented Oct 10, 2024

Description

Hello,
I'm having troubles with an issue that is quite similar to this one : #41067
I am using quarkus OidcClientRequestReactiveFilter that is working very good but in my specific case i dont have an expire time returned by sales force so my token is considered always valid.
The problem is that this token can expired or revoked and in this case i am getting 401.
At first i thought i could catch this 401 error and force refresh the access token but i didnt find a way. All i can do is requesting a new token but it is not propagated into the TokensHelper context so during the next call, it uses the old revoked token (i have retries enabled on my call).
It would be nice to have a method that can force refresh the context by requesting a new access token not depending only on the expiration time.
Moreover i was wondering if you have an idea of how i could handle this case at the moment?

Here is an example of my calling method :

@Retry(retryOn = RetryException.class)
    public void postPO(ProductOrder po, String partnerName) throws RetryException {
        try {
            LOGGER.debug(ELogId.CONN_PO_SVC__CALL_PARTNER, "Calling partner : %s", partnerName);
            client.productOrderCreate(po);
        } catch (RestClientException e) {
            e.setOrigin(partnerName);
            if (e.getResponse().getStatus() == 401) {
                //TODO force refresh the token
                throw new RetryException(e, ECommonErrorResponse.CALL_ERROR_GENERIC_PARTNER, partnerName);
            }
            if (retryCodes != null && retryCodes.contains(e.getResponse().getStatus())) {
                throw new RetryException(e, ECommonErrorResponse.CALL_ERROR_GENERIC_PARTNER, partnerName);
            } else {
                throw new RestException(e, null, partnerName, null, ECommonErrorResponse.CALL_ERROR_GENERIC_PARTNER, partnerName);
            }
        } catch (ProcessingException e) {
            throw new RestException(e, null, partnerName, null, ECommonErrorResponse.PARTNER_GENERIC_PRODUCT_ORDER_UNAVAILABLE,
                                    partnerName);
        }
    }

And my client interface :

@RegisterProviders({@RegisterProvider(RestClientExceptionMapper.class), @RegisterProvider(OidcClientRequestReactiveFilter.class)})
@Path("/productOrder")
public interface ProductOrderApi {
    @POST
    @Consumes({"application/json;charset=utf-8"})
    @Produces({"application/json;charset=utf-8"})
    ProductOrderResponse productOrderCreate(@Valid ProductOrder productOrder) throws RestClientException;
}

Implementation ideas

No response

Copy link

quarkus-bot bot commented Oct 10, 2024

/cc @pedroigor (bearer-token,oidc)

@sberyozkin
Copy link
Member

sberyozkin commented Oct 10, 2024

@AJO35813 Hi,

When you use a filter, and you need to force refresh what looks like a valid token to the filter, the only way is to register a custom filter extending the default one and only overriding a single method, isForceNewTokens, for example: #41067 (comment) (you can do something similar) - this effectively causes a new token acquisition.

Let's say the filter sent what it sees as a valid token to the target - but you got 401 because as it happens the token was revoked in the provider. In this case you can probably coordinate via a bean which is injected into this custom request filter, and custom JAX-RS client response filter: the response filter will record in the bean that a refresh is required if 401 is returned and then, when the retry is made, the custom request filter will force the new token acquisition by returning true. Something along these lines.
Or you can force a new token acquisition after it was used 3 times etc, or even every time.

This will resolve your code example above - the retry goes and the token is renewed.

However, #43417 also makes it possible to set a fixed expiration period, so you don't even have to override anything, just set that property and it will refreshed say every 3 mins.

You can also set a refresh token skew to refresh proactively - so that it is refreshed say if it is within 30 secs of its expiration time - this will guarantee you will never really get a situation where the valid token was sent but got expired by the time it reached the target.

If you prefer you can get a full control, get OidcClient created directly, for example (check OidcClientCreator), and in case of 401, call its refreshAccessToken method.

To summarize, the only way to force a refresh of what looks like a valid token at the filter level is to register a simple custom extension filter. You can prevent expiration related errors by doing the proactive refresh.
And alternatively, you can control OidcClient directly.

Does it address your concerns ?

@IvanPuntev
Copy link
Contributor

@sberyozkin What will be the client behavior if both properties are set?

quarkus.oidc-client.credentials.jwt.lifespan=
quarkus.oidc-client.access-token-expires-in=

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/oidc kind/enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants