-
Notifications
You must be signed in to change notification settings - Fork 5.9k
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
Introduce Bearer Token prefetch and background refresh for WebClient Oauth2 #9560
Comments
This is application-specific behaviour so it would need to be implemented in the application itself. Our focus is to provide protocol (spec) implementations only within the framework. Please take a look at the comments in gh-7676 as a solution is provided there along with a Stack Overflow answer. I'll close this as a duplicate. |
@jgrandja I think it's fair design decision if you want keep such behaviour outside of framework, as sufficient API is exposed to inject your own behavior. This is exactly what we did. Thank you for clarification and pointer, this confirms we had right idea :). I don't want to spam new issues without asking, so let me ask here: Is there something I am missing? Should I raise another issue? |
I believe this can be achieved via Please log a new issue and /cc @jzheaux as he would be able to help out. |
Unfortunately Thank you very much for your help, I really appreciate it. I will create issue. |
Ok disregard my comment. There is |
Expected Behavior
Introduce opt-in API to initialize Bearer Token before first request, and to refresh this token periodically in background.
Current Behavior
Currently, WebClient configured with Bearer Token authentication like Client Credentials will not retrieve token unless request is made (which I think is proper default behavior), also, when token expires, new token will be fetched only when next request is done.
This is ok for default case, but it introduces delays in request processing at random moments.
Sometimes you are willing to pay some cost of prefetching token before use, and periodically fetching it in background to make sure requests will not be delayed. This is not possible with current implementation.
Context
We have rest microservice (let's call it A) that has other rest microservice as dependency (B), which is read with WebClient configured with Client Credentials for authentication, with external authorization server. Pretty common scenario.
Only after first request arrives to A and request is triggered to B WebClient fetches token, so first request to A is delayed by time required to retrieve token, in our case it was 2s, so much to long, causing request to fail because of timeout.
Same situation happens when token expires - either token is valid and used for request, or is considered expired and request is delayed until new token is fetched.
I was able to implement own
ClientCredentialsReactiveOAuth2AuthorizedClientProvider
that will refresh token in background when it is beyond some lifetime threshold, still using old token until it's ready. But maybe this could be also useful for everyone else?More complex thing is with prefetching (before first request) and refreshing even when there are no requests.
For prefetching, I was able to do it by creating proxy
AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager
that had some preconfiguredOAuth2AuthorizeRequest
injected, and would trigger authorization request with it. It works, but I don't like it as it breaks responsibilities. But I was not able to find any API that could be used.For periodic refresh (that would trigger without any request to this webclient) there is an issue that there needs to be some handle to stop refreshing, preferably without user intervention when WebClient is not used anymore.
Note
There is symmetric issue on server side with JWK fetch - it is only fetched when it is needed, delaying first request. Should I include it here or raise another issue?
Implementation details for solution I made
For
ClientCredentialsReactiveOAuth2AuthorizedClientProvider
I check if token is valid. If not, current implementation is used (blocking request until token is fetched). If valid, I calculate token lifetime, and when token is past percentage of lifetime I issue request in background if not issued already, and returnMono.empty()
to trigger usage of old token. To simplify implementation I useMono.cache()
to create cached hot source of tokens, then use Mono.or() to select new token when it is ready in cache, as intokenMonoCached.or(Mono.empty())
. This will immediately return result, either new token or empty, but assumes thatMono.or()
will evaluate in order of arguments toor
. While it works this way I was not able to find confirmation in reactor docs. But if this is not like this it could be reworked to someAtomic<>
.For
AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager
I wrote some proxy that acceptsOAuth2AuthorizeRequest
as costructor parameter, and exposesstart()
andstop()
APIs to trigger initial token fetch and start periodic requests. Periodic requests are triggered once i a while (configurable) withFlux.interval()
.As I mentioned, I'm not a fan of this solution because it requires
AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager
to have some preconfiguredOAuth2AuthorizeRequest
and is not usable for generic case.Periodic trigger of
.authorize()
should not be a problem, as when token is valid it will just check validity and return empty mono.The text was updated successfully, but these errors were encountered: