I am getting confused by the spring security configuration. For example, I am developing a Spring-boot application. In project resources/application.yml
, I can configure it as below to communicate with Keycloak(or any other OAuth2 server):
spring:
security:
oauth2:
client:
registration:
spring-app:
client-id: spring-app
client-secret: VWsQaq02oUYaWNzb51dKzACrF5QLgTm8
authorization-grant-type: authorization_code
scope: openid, profile, roles
redirect-uri: http://localhost:8080/login/oauth2/code/spring-app
provider:
spring-app:
issuer-uri: http://localhost:8383/realms/foo
If I shrink above configuration to highlight the key things for my question later:
spring:
security:
oauth2:
client:
registration:
spring-app:
...
...
provider:
spring-app:
issuer-uri: http://localhost:8383/realms/foo
I am basically configured my project as an OAuth2 client, and I also tell who is the OAuth2 server provider (Keycloak in my case, but it can be any other OAuth2 server).
But If I change the configuration completely to the following one in the same spring-boot project:
spring:
security:
oauth2:
resourceserver:
jwt:
jwk-set-uri: ${spring.security.oauth2.resourceserver.jwt.issuer-uri}/protocol/openid-connect/certs
issuer-uri: http://localhost:8383/realms/foo
As you can see, above configuration is a resourceserver
(Resource Server) configuration, which treats my spring-boot application as a resource server instead of client in the context of OAuth2. The endpoints exposed by my spring-boot controllers are also protected by keycloak with this configuration (which I've tested), as long as the issuer-uri
is pointing to keycloak uri.
I get very confused on when should I do client configuration and when should I do resource server configuration for my spring-boot project when using Spring Security?
I see both make sense, because my spring application is indeed an OAuth2 client being registered in Keycloak, and also my spring application is indeed a resource server which has endpoints exposed that should be protected by OAuth2 flow(s).
Could someone please clarify this for me, when to use which? Thanks in advance!
Dependencies in my project to verify things:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web:3.2.3'
implementation 'org.springframework.boot:spring-boot-starter-security:3.2.3'
// oauth2 client
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client:3.2.3'
// oauth2 resource server
implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server:3.2.3'
...
An OAuth2 resource server processes requests from an OAuth2 client. So you use:
Note that:
oauth2Login
in Spring conf), the security is based on sessions, which requires protection against CSRF. In other words, when you send a request to a Spring app with oauth2Login
, the request authorization is made with a session cookie, not a Bearer
token. Also, it is generally expected that such an app responds with 302 redirect to login
to unauthorized requests to prtocted resources.Bearer
access tokens. It is generally expected that such an app responds with 401 unauthorized
to unauthorized requests to prtocted resources.An application can be configured as both a client with oauth2Login
and as an oauth2ResourceServer
, but because of the very different security conf between the two, in such a case, I configure a separate Security(Web)Filterchain
bean for each. For instance, my BFFs always are configured that way because it is a client by nature but also exposes REST endpoints like Actuator ones.
When resource servers call each others using client-credentials, client dependencies and conf are required to fetch the new tokens used in this inter service calls. But no need for a separate security filter-chain.
In the case where a service configured as a resource server calls another resource server on behalf of the resource owner who originated the request, it can forward the access token it received. In this case, the caller is a client for the other service, but doesn't need client deps and conf: the token is taken from the security context, not from the authorization server.
If you like to, you might find some more OAuth2 background and configuration tutorials from this Github repo of mine