This question should not be answered because:
- it is actually a container for many questions
- quite a few are way too wide or lack precision.
But as it seems to be a first question... (break it down next time, give more details and edit your question when you get comments asking precisions)
0. Usefull Resource
I maintain up to date samples and tutorials covering most OAuth2 use-cases with Spring for both reactive applications and servlets. Start with tutorials main README if you are new to OAuth2 with Spring.
1. Where need to use spring-boot-starter-oauth2-client
and spring-boot-starter-oauth2-resouce-server
?
This one is important to start with as I suspect you lack OAuth2 background, specifically regarding involved parties and how it is implemented with spring-security:
spring-boot-starter-oauth2-client
is to be used with OAuth2 clients:
- apps serving UI with
oauth2Login
(@Controllers
with methods returning template names)
- apps consuming REST APIs with auto-configured Spring client:
WebClient
, @FeignClient
, RestTemplate
spring-boot-starter-oauth2-resouce-server
is to be used with resource-servers: apps serving REST APIs (@RestController
or @Controller
with @ResponseBody
)
Now, if your app has controllers for both the resources and the UI to manipulate it (with Thymeleaf or any other server-side rendering engine), then define two different security filter-chains: one for each, ordered, and with securityMatcher
in the first in order to limit the routes it applies to (the second being used as fallback for unmatched routes). Sample in this answer (the sample is for servlet, but it's the exact same principles): Use Keycloak Spring Adapter with Spring Boot 3
2. Is spring-boot-starter-oauth2-resouce-server
also use to authentication?
OAuth2 requests should be authorized with an Authorization
header containing a Bearer
access-token.
The client is responsible for acquiring such an access-token from the authorization-server before sending requests to resource-server.
Your question is not quite clear but here are a few statements which could answer:
- resource-server should return 401 (unauthorized) and not 302 (redirect to login) when authorization is missing or invalid => do not configure
oauth2Login
in resource-server filter-chain. Again, this is client business
- resource-server is responsible for resources access-control: check that access-token is valid, that the user has required authorities, etc.
3. How to authenticat user using spring-boot-starter-oauth2-client
and pass to spring-boot-starter-oauth2-resouce-server
for authorization.
This question is not focused enough to get a single answer: what kind of client? what kind of request? context?
I see three main cases here:
- the UI is rendered on Spring server with Thymeleaf, JSF, and alike => use spring's
oauth2Login
and refer to its documentation to overrides defaults and implement your authorization-server selection logic
- the UI is rendered in the browser (Angular, React, Vue, ...) and you are ok to make it an OAuth2 client => find a certified client lib for your framework and implement the logic in the client (angular-auth-oidc-client, for instance, supports multi-tenancy)
- the UI is rendered in the browser, but you prefer to implement the Backend For Frontend pattern to hide tokens from browser, then choose a BFF (like
spring-cloud-gateway
with tokenRelay
filter) and refer to its doc for implementing your logic in it
If that can be of any help, I have:
- here a tutorial for configuring an app with a Thymeleaf UI client and REST API
- there a sample repo with an Angular workspace (app configured as OIDC client + API client lib generated from OpenAPI spec) and spring-boot resource-server (using servlet, but this makes no difference to the client).
4. How to implement multi-tenacy e.g. take tenant id from url and redirect user to tenant specific keycloak login page
Note
One of key principles of OAuth2 is that identities (tokens) are emitted (issued) by trusted 3rd parties (authorization-servers) => you must configure the list of issuers your resource-servers can trust (and clients can fetch tokens from). This list is static (loaded with conf at startup). The only reasonable trick for "dynamic" multi-tenancy is configuring an authentication manager resolver for a given host and dynamically creating authentication manager for new realms on this host. There is a tutorial covering that case among those linked at point 0.
Accept identities from various issuers on the resource-server
This is done by overriding the default ReactiveAuthenticationManagerResolver<ServerWebExchange>
in your SecurityWebFilterChain
configuration: http.oauth2ResourceServer().authenticationManagerResolver(authenticationManagerResolver)
I provide with thin wrappers around spring-boot-starter-oauth2-resource-server
which support "static" multi-tenancy just by defining properties. Complete sample there:
Instead of spring-boot-starter-oauth2-resource-server
(which is a transient dependency):
<dependency>
<groupId>com.c4-soft.springaddons</groupId>
<artifactId>spring-addons-webflux-jwt-resource-server</artifactId>
</dependency>
Instead of all your resource-server Java conf (unless you want access control from configuration and not with method-security, in which case, you'd have to define an AuthorizeExchangeSpecPostProcessor
bean here). Of course, you'll have to add here a client filter-chain with a restrictive securityMatcher
if you also serve UI client with oauth2Login
:
@EnableReactiveMethodSecurity
@Configuration
public class SecurityConfig {
}
Instead of spring.security.oauth2.resourceserver
properties:
com.c4-soft.springaddons.security.issuers[0].location=https://localhost:8443/realms/realm-1
com.c4-soft.springaddons.security.issuers[0].authorities.claims=realm_access.roles,resource_access.client-1.roles,resource_access.client-2.roles
com.c4-soft.springaddons.security.issuers[1].location=https://localhost:8443/realms/realm-2
com.c4-soft.springaddons.security.issuers[1].authorities.claims=realm_access.roles,resource_access.client-1.roles,resource_access.client-2.roles
# Comma separated list of routes accessible to anonymous
com.c4-soft.springaddons.security.permit-all=/api/v1/public/**,/actuator/health/readiness,/actuator/health/liveness
# Fine-grained CORS configuration can be set per path as follow:
com.c4-soft.springaddons.security.cors[0].path=/api/**
com.c4-soft.springaddons.security.cors[0].allowed-origins=https://localhost,https://localhost:8100,https://localhost:4200
# this are defaults and can be omitted
com.c4-soft.springaddons.security.cors[0].allowedOrigins=*
com.c4-soft.springaddons.security.cors[0].allowedMethods=*
com.c4-soft.springaddons.security.cors[0].allowedHeaders=*
com.c4-soft.springaddons.security.cors[0].exposedHeaders=*
If you don't want to use "my" wrappers, just copy from the source, it is open.
Redirect the user to the right authorization-server from client UI
As explained at point 3., this depends on the kind of client, used framework and if BFF pattern is applied or not
5. I tried some example but won't succeed, working example will be helpful with - Spring Webflux + spring-boot-starter-oauth2-client
+ spring-boot-starter-oauth2-resouce-server
+ multi-tenancy + keycloak as a provider
With all the elements above and linked resources, you should have enough to find your own path