8.0.2
is 🚀. It is designed to work with Spring Boot 3.4.1
(Security 6.4.2
and Cloud 2024.0.0
). See the release notes for details.
The new spring-addons-starter-rest
can be a game changer for inter-service calls when OAuth2 or an HTTP proxy is involved. Give it a try!
This repo hosts tutorials for configuring Spring RESTful backends with OAuth2 / OIDC. Carefully read the OAuth2 essentials section before jumping into implementation.
Three tutorials from this repo have been moved to Baeldung:
- Getting started with Keycloak & Spring Boot
- Creating an OAuth2 BFF with
spring-cloud-gateway
and consuming it with Single-Page Applications - Testing access control with mocked OAuth2 authentications
When using just spring-boot-starter-oauth2-client
or spring-boot-starter-resource-server
we almost always end up writing the Security(Web)FilterChain
ourselves, which requires a solid security background, some knowledge of Spring Security internals, and can be verbose.
spring-addons-starter-oidc
builds on top of "offical" starters to significantly reduce the need for security configuration code. It even brings it down to 0 in most cases.
We have complete control over what spring-addons-starter-oidc
auto-configures. With application properties, of course, but also bean definitions: almost all auto-configured components are @ConditionalOnMissingBean
, meaning that spring-addons
backs off each time a component is explicitly defined in an application. But no need to define a complete security filter-chain, defining just the component to override should be enough.
Auto-configuration for resource servers:
- accepting tokens issued by several trusted authorization servers
- mapping authorities from a variety of claims (including nested ones), with custom prefix and case
- CORS configuration
- allowing anonymous preflight requests using the path-matchers in CORS configuration
Auto-configuration for clients with oauth2Login
:
- customizing responses returned to the frontend during the authorization-code and RP-Initiated Logout flows:
- specify the URI in
Location
header to activate a route after login / logout (defaults can be defined in application properties and overridden by the frontend using headers or query parameters) - avoid some CORS issues with the authorization server: set the HTTP status in the
2xx
range to observe the response and handle the redirection in Javascript code instead of letting the browser follow with an Ajax request. There is no reason for these redirections to be cross-origin requests, plain navigation is what should actually happen.
- specify the URI in
- exposing CSRF token as a cookie accessible to a single-page application
- logging out from an authorization server not strictly implementing RP-Initiated Logout (case of Auth0 and Amazon Cognito for instance)
- activating and configuring Back-Channel Logout
- adding extra parameters to authorization & token requests (like the
audience
required by Auth0) - CORS configuration
- allowing anonymous preflight requests using the path-matchers in CORS configuration
At an age where OpenAPI specs can be generated from REST APIs source code, and the client code to consume these APIs generated from the specs, the main challenge for inter-service communication is the configuration of REST clients.
Spring promotes the usage of RestClient
or WebClient
, but configuring those for Basic
or Bearer
authentication, an HTTP proxy, and connection & read timeouts is pretty complicated, verbose, and error-prone.
spring-addons-starter-rest
makes this configuration a snap.
Sample usage
com:
c4-soft:
springaddons:
rest:
client:
# Exposes a RestClient bean named machinClient (or WebClient in a WebFlux app)
machin-client:
base-url: ${machin-api}
authorization:
oauth2:
# Authorize outgoing requests with the Bearer token in the security context (possible only in a resource server app)
forward-bearer: true
# Exposes a RestClient.Builder bean named biduleClientBuilder (mind the "expose-builder: true")
bidule-client:
base-url: ${bidule-api}
# Expose the builder instead of an already built client (to fine tune its conf)
expose-builder: true
authorization:
oauth2:
# Authorize outgoing requests with the Bearer token obtained using an OAuth2 client registration
oauth2-registration-id: bidule-registration
This exposes pre-configured RestClient
or WebClient
beans (or their builders) that we can auto-wire in any kind of @Component
- like @Controller
& @Service
- or use in @Configuration
- for instance to generate implementations of @HttpExchange
interfaces and expose them as beans.
Proxy configuration is applied by default to REST clients as soon as the HTTP_PROXY
and NO_PROXY
environment variables are set. This can be overridden and disabled with application properties.
Testing access control requires configuring the test security context with a fine-tuned Authentication
instance.
For that, spring-security-test
provides MockMvc
request post-processors and WebTestClient
mutators, but it can work only in the context of a request, which limits its usage to controllers. To test any type of @Component
(@Controller
, of course, but also @Service
and @Repository
) there are only two options:
- build tests security context by ourself and populate it with stubbed / mocked authentications 😢
- use annotations to do it for us (this is where spring-addons-oauth2-test jumps in) 😃
Also, a notable difference between @MockJwt
and those in spring-security-test
is that spring-security-test
ignores the authentication converter defined in the security conf 😭. To understand the consequences, let's consider the flow to build the security context in a resource server with a JWT decoder:
- the JWT Bearer string is decoded, validated, and turned into a
org.springframework.security.oauth2.jwt.Jwt
by aJwtDecoder
- this
Jwt
(not JWT) is turned into something extendingAbstractAuthenticationToken
by an authentication converter. This step includes converting claims to authorities and the choice of a specificAuthentication
implementation. - the
Authentication
instance is put in the security context
With @WithJwt
, only the 1st step is mocked. A stub Jwt
(not JWT) is built using a JSON payload in test resources and provided to the authentication converter. With spring-security-test
post-processors and mutators, factories skip to step 3 and build a stub Authentication
themselves, setting properties with what is provided in the test code. So, authorities conversion logic is used only with @WithJwt
. Similarly, a custom Authentication
implementation will be used in tests only if the authentication converter is called by the factory, and as so, with @WithJwt
, but not with .jwt()
post-processor.
Useful resources:
- spring-addons-oauth2-test contains test annotations and its README documents usage
- spring-addons-starter-oidc-test if you use
spring-addons-starter-oidc
- Baeldung article
- samples and tutorials source-code (which contain a lot of unit and integration testing)
spring-addons-starter-oidc
a Spring Boot starter pushing OAuth2 clients & resource server security auto-configuration to the next levelspring-addons-oauth2-test
annotations for populating test security-context with OAuth2 authentication instancesspring-addons-starter-oidc-test
ease unit-tests in applications usingspring-addons-starter-oidc
spring-addons-starter-rest
experimental auto-configuration forRestClient
,WebClient
and@HttpExchange
proxies (base-URL, Basic & OAuth2 Bearer auth)- Getting started with Keycloak & Spring Boot
- OAuth2 security configuration tutorials (with and without
spring-addons-starter-oidc
) - OAuth2 BFF tutorial
- Release Notes
- Maven-Central Reminders