Summary

Today, it isn't clear how to best configure Spring Security to support a multi-tenant OAuth2 client.

Here is an example of one approach out in the wild:

https://github.com/thomasdarimont/spring-boot-2-keycloak-oauth-example/blob/feature/mulit-tenancy/src/main/java/demo/SpringBoot2App.java#L127

Though whether JwtDecoder is the ideal place and how tenants might possibly be treated in a more first-class way is yet to be seen. Opening this issue to get the conversation started.

Comment From: bertramn

We indeed had the requirement to run a single resource server that can validate JWTs issued by multiple issuers. We had to implement our own given the Spring one does not support this and Keycloak adapters only support Keycloak specific issuers.

We had 2 main use cases for multi tenancy:

  1. validate all inbound JWT with an Issuer whitelist

This use case requires the IssuerResolver to lookup (and cache) issuer metadata JWKS certs.

  1. validate inbound JWT based on a pre-configured list of issuers

This use case requires a pre-configured IssuerResolver which is configured with the issuer (iss) name it supports and then either the metadata url or the public cert, where the later does not really work well if your issuer performs key rotation.

Another interesting aspect we ran into was that if we just want to run a API based resource server (ie. Spring Boot micro service) there will be a lot of unnecessary moving parts in the Spring Security configuration. We ended up implementing 3 components (AccessDeniedHandler, AuthenticationFailureHandler and AuthenticationEntryPoint), everything else is surplus and massively overcomplicates things.

Comment From: jgrandja

Related #5385

Comment From: metacubed

In a multi-tenant configuration, each tenant would likely come with its own set of allowed issuers. A tenant-specific request would trust only a subset of the issuers configured for the resource server.

We would need to introduce a selection mechanism to pick the allowed issuer(s) for a request. This IssuerListSelector could have custom implementations that are specific to the resource server.

For example, the keycloak-auth project uses the request.getServerName() to decide which decoder implementation to use. Other request attributes could also be used, such as the request sub-domain, a header, etc.

Comment From: canayozel

@jzheaux since this is released with spring security 5.2.0 is there any documentation or example to follow ? (Not only for resource server but oauth2 clients included)

Comment From: jzheaux

@canayozel Multi-tenancy support for clients is had through multiple client registrations: https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#oauth2login-custom-provider-properties

For resource server, we have a sample, but are still on the hook for adding documentation.

Comment From: bertramn

Hmm not too sure how the multi tenant example is of use to anyone wanting to run a Resource Server that can validate JWTs from different issuers. It just flip-flops the AuthenticationManager back and forth between paths. And I thought we finally could replace our custom implementation.

Comment From: jzheaux

@bertramn, you are right that 5.2.x doesn't support any specific multi-tenancy model for resource servers. AuthenticationManagerResolver gives applications a place to address their multi-tenancy use case, be it whatever it may. In 5.2.x, there is just the interface and DSL hook.

7724 demonstrates one way Spring Security might be able to support your use case for JWTs and multiple issuers - feel free to comment over there how well that implementation simplifies your customizations.

Comment From: 20fps

Thanks a lot for this video https://www.youtube.com/watch?v=ke13w8nab-k It answered all of my questions on multi-tenancy