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

please support lazily doing issuer checks (and all other checks) on startup for oauth resource servers #9991

Closed
joshlong opened this issue Jun 22, 2021 · 5 comments · Fixed by #10310
Assignees
Labels
in: oauth2 An issue in OAuth2 modules (oauth2-core, oauth2-client, oauth2-resource-server, oauth2-jose) type: enhancement A general enhancement
Milestone

Comments

@joshlong
Copy link
Member

right now the app is slowed a bit by HTTP checks it has to make when the app startsup. other implementations do a lot of these HTTP requests lazily, on the first use. this means that developers don't have to pay the sometimes significant cost of making the HTTP request to slow providers unless they trigger a request that needs it for their dev iteration cycle

@joshlong joshlong added status: waiting-for-triage An issue we've not yet triaged type: enhancement A general enhancement labels Jun 22, 2021
@eleftherias eleftherias added in: oauth2 An issue in OAuth2 modules (oauth2-core, oauth2-client, oauth2-resource-server, oauth2-jose) and removed status: waiting-for-triage An issue we've not yet triaged labels Jun 23, 2021
@jzheaux jzheaux assigned jzheaux and unassigned sjohnr Jun 30, 2021
@jzheaux
Copy link
Contributor

jzheaux commented Jun 30, 2021

Hey, @joshlong!

The following setup is the preferred way to defer HTTP calls on startup:

spring.security.oauth2.resourceserver.jwt.jwk-set-uri=http://authz.example.org/jwks
spring.security.oauth2.resourceserver.jwt.issuer-uri=http://authz.example.org

If the jwk-set-uri property is present, then Spring Security will do checks lazily. This is because it relies on Nimbus, which operates lazily.

Here is a sample where these two properties point to an intentionally slow endpoint. The endpoint is configured to take 30 seconds to reply; however, the app still starts up in less than 2 seconds. This implies that no HTTP requests are getting made when the sample starts up.

Using that sample, you can try the following:

export TOKEN="eyJraWQiOiJjOWEyMzIxYy01N2NmLTQ1YmYtOWIzYS1kYjdjYzk3ODkwZTEiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c2VyIiwiYXVkIjoiZ29hbHMtY2xpZW50IiwibmJmIjoxNjI0OTk1ODMwLCJzY29wZSI6WyJnb2FsOnJlYWQiLCJ1c2VyOnJlYWQiLCJnb2FsOndyaXRlIl0sImlzcyI6Imh0dHBzOlwvXC9vYXV0aDIucHJvdmlkZXIuY29tIiwiZXhwIjoxNjI0OTk5NDMwLCJpYXQiOjE2MjQ5OTU4MzAsImp0aSI6IjM5OWIzMWUxLWZlNDItNDQwNS1iYjY0LWVkYmY5YTQ1M2I4ZSJ9.Z8Jy3JhFDK7Ijv9IWT9taLTbXXiXw8Eb0ZO2mD4pRFVLODYfAXLpt-fx5j9ZiApsrejj0pvyCBXOnjsroG8spZmSEHNlUO4_eVlrBtuB3pF54E7jDF6CrnS5nP2u5CSfsXAPoXqzcxHyghQ-n0vtaKhuCbgpVUyV6w5Gye7JrQa-Sj7eIPv4CfumC9vbphrnjVOlQvF_i7qJnp4cnDFM5AuGPkzdmOy_7nTwaYgXczyp4_2Qr4qPhju38g-GK-6S2YtPSmy5tgLGoMgllRU5elVmHZ5jddZAmnVu4couNM9jDxfIU3g3cfGiVSDVdXoqR3E2mpLuHn45Ml2mkmNl5g"

http :8080 "Authorization: Bearer $TOKEN"

and the request will timeout, having taken 30 seconds to get a reply from the JWKS endpoint.

I remember that you and Matt Raible were experiencing something different, though, where startup seemed to be different based on internet speeds. Can you share a sample that is making those HTTP calls on startup and we can take a look?

@mraible
Copy link
Contributor

mraible commented Aug 13, 2021

Hello, @jzheaux!

I published a blog post with my findings on the Okta developer blog. See the build native images section to see how to build each example and run it. It also explains what we found.

You can find all the code in https://github.com/oktadev/native-java-examples.

@jzheaux
Copy link
Contributor

jzheaux commented Oct 5, 2021

Hi, @mraible, @joshlong. I noticed something in Matt's blog post that I didn't before. I want to make sure that this ticket is resolving the issue you identified, and the way I read it this afternoon made me think that there might be more to discuss.

It says:

Our hypothesis is Micronaut and Quarkus do the JWKS lookup on the first request rather than at startup. That’s how they achieve faster startup times.

I think there's more to this since Micronaut, Quarkus, and Boot all three already do the JWKS lookup on the first request rather than at startup. I think their faster startup times are due to something else.

... Follow this Spring Security issue to see when Spring Security adds lazy OIDC discovery support.

This ticket indeed combined with spring-projects/spring-boot#28122 adds lazy OIDC discovery support. But your second experiment already disables OIDC discovery, so even with these changes your second chart will stay the same.

IOW, after updating to Boot 2.6, your first chart and your second chart will be the same as the current second chart.

Is that what you would have expected? If not, we can reopen the ticket to take a second look.

FWIW, when I run the Boot sample from the blog post, I can confirm that Boot already does the JWKS lookup on the first request rather than at startup. I confirmed this by deploying a local authorization server and watching the request logs.

@mraible
Copy link
Contributor

mraible commented Oct 11, 2021

Thanks for the clarification, @jzheaux. Will I need both the JWKS URI and issuer to trigger lazy-loading in Spring Boot 2.6? Or will using either one result in lazy-loading? If I want eager-loading instead, how do I configure that?

@jzheaux
Copy link
Contributor

jzheaux commented Oct 13, 2021

Good questions, @mraible.

Will I need both the JWKS URI and issuer to trigger lazy-loading in Spring Boot 2.6?

No. In 2.6 both the JWK Set URI and its public keys will be lazily fetched when supplying an issuer-uri. (In 2.5, only the public keys are lazy.)

This will cause the first HTTP request to be longer since it now has more work to do. Applications that additionally provide a jwk-set-uri will see equivalent startup times, but a faster first HTTP request.

Or will using either one result in lazy-loading?

If only issuer-uri is provided, the JWK Set URI and keys are not fetched until the first HTTP request.

If both issuer-uri and jwk-set-uri are provided, then the keys are not fetched until the first HTTP request (same as 2.5).

If I want eager-loading instead, how do I configure that?

If you want the URI and keys to be fetched eagerly, you can configure the bean yourself, like so:

@Bean 
JwtDecoder eagerJwtDecoder() {
    return JwtDecoders.fromIssuerLocation(issuerUri);
}

If you want only the keys to be eager, this isn't something that Spring Security supports. But, I believe you can get it by querying the RemoteJWKSource yourself, and then providing that RemoteJWKSet to the NimbusJwtDecoder as is done in JwtDecoders.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: oauth2 An issue in OAuth2 modules (oauth2-core, oauth2-client, oauth2-resource-server, oauth2-jose) type: enhancement A general enhancement
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants