I think it would be useful to disable the OAuth2 / OIDC discovery explicitly. At this moment this is possible implicitly by configuring every necessary detail of the clients registration and provider but skipping the providers issuerUri. This disables the discovery via OAuth2ClientPropertiesMapper.

Why

  • Someone wants the service to not require the IdP to be available at startup.
  • Some code may need the issuerUri to function properly.

In fact, there already is such code: Spring Securitys OIDC back channel logout validates the providers issuerUri in OidcBackChannelLogoutTokenValidator and ends up with a NPE if you did not set an issuerUri.

So setting the issuerUri means you are forced to use discovery. Leaving it null means no working back channel logout, at least not with auto configuration.

How?

I'm not quite sure. Maybe a new property:

# default (fallback) value: true
spring.security.oauth2.client.provider.MY_PROVIDER.discovery=false

Setting this to false would opt-out the discovery. The current behaviour should be kept as default.

Comment From: knoobie

+1 / We also have strong requirements that systems should not depend on other systems while starting - so we are also forced to manually configure everything. This leads to interesting problems when e.g. the oauth provider changes something and our configuration gets out of date - which in turn creates hard to troubleshoot problem at first glance.

Comment From: wilkinsona

This leads to interesting problems when e.g. the oauth provider changes something and our configuration gets out of date

How would disabling discovery help with that? I don't understand how it would help to keep your configuration in sync with that of your OAuth provider.

Comment From: knoobie

How would disabling discovery help with that? I don't understand how it would help to keep your configuration in sync with that of your OAuth provider.

Good question, Andy! I went a little bit overboard and interpreted a bit too much into the issue, like e.g. true/false and "lazy" loading of the configuration - allowing the application to start, but retrieve the required information on first access.

Comment From: philwebb

@jgrandja do you have any thoughts on this suggested change?

Comment From: jgrandja

@delbertooo

Some code may need the issuerUri to function properly.

In fact, there already is such code: Spring Securitys OIDC back channel logout validates the providers issuerUri in OidcBackChannelLogoutTokenValidator and ends up with a NPE if you did not set an issuerUri

I can't recall, but the issuerUri may be required for the OIDC back channel logout. @jzheaux Would be able to answer this one.

Someone wants the service to not require the IdP to be available at startup.

The SupplierClientRegistrationRepository added in gh-12967 could solve this issue as the issuer lookup is deferred on first access.

@philwebb Maybe the solution is to wrap the InMemoryClientRegistrationRepository @Bean

https://github.com/spring-projects/spring-boot/blob/f78ec43dd61a202dd224637c375a0d64280e5bfc/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientRegistrationRepositoryConfiguration.java#L47

in a SupplierClientRegistrationRepository?

Comment From: jzheaux

Yes, the issuer URI is required for back-channel logout due to how ID Tokens are validated.

As a side note, it would certainly be reasonable to give a better error response. I've added https://github.com/spring-projects/spring-security/issues/15771 to address that.

Comment From: delbertooo

The SupplierClientRegistrationRepository added in gh-12967 could solve this issue as the issuer lookup is deferred on first access.

@philwebb Maybe the solution is to wrap the InMemoryClientRegistrationRepository @Bean

https://github.com/spring-projects/spring-boot/blob/f78ec43dd61a202dd224637c375a0d64280e5bfc/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientRegistrationRepositoryConfiguration.java#L47

in a SupplierClientRegistrationRepository?

@jgrandja Yes, this kind of works and is our current solution / workaround:

    @Bean
    public SupplierClientRegistrationRepository clientRegistrationRepository(OAuth2ClientProperties properties) {
        return new SupplierClientRegistrationRepository(() -> {
            log.info("Loading OAuth2 client registrations");
            final var registrations = new OAuth2ClientPropertiesMapper(properties).asClientRegistrations();
            return new InMemoryClientRegistrationRepository(registrations);
        });
    }

Works for some scenarios. Might break if one uses oauth2Login with the default generated login page, because the login page works with login links from the repository and is built at application boot. Therefore the application cannot boot without the provider.

This leads me to the question: is it desirable to configure a provider completely without the need of discovery? Or would it be more straight forward to have a local copy of the configuration metadata and use the discovery against the local file copy?

Comment From: jgrandja

@delbertooo

Might break if one uses oauth2Login with the default generated login page

Yes, you are right, it would break if the provider configuration endpoint was not accessible at startup time. Although the generated login page is only meant to be used at development/test time and not production, we would need to ensure it doesn't break regardless.

is it desirable to configure a provider completely without the need of discovery? Or would it be more straight forward to have a local copy of the configuration metadata and use the discovery against the local file copy?

It depends on the requirements of your application environment. The way I see it is if your application needs access to the provider configuration endpoint then it needs to ensure the provider is up and running at startup. But if it needs to be more resilient at startup and not depend on the provider then you should be explicit on the provider configuration and not depend on issuer-uri or use SupplierClientRegistrationRepository.