diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc
index 91e7b9960f..17da165d64 100644
--- a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc
+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc
@@ -208,6 +208,9 @@ Methods on the `oauth2ResourceServer` DSL will also override or replace auto con
For example, the second `@Bean` Spring Boot creates is a `JwtDecoder`, which decodes `String` tokens into validated instances of `Jwt`:
+
+.JWT Decoder
+====
[source,java]
----
@Bean
@@ -215,6 +218,7 @@ public JwtDecoder jwtDecoder() {
return JwtDecoders.fromIssuerLocation(issuerUri);
}
----
+====
[NOTE]
Calling `{security-api-url}org/springframework/security/oauth2/jwt/JwtDecoders.html#fromIssuerLocation-java.lang.String-[JwtDecoders#fromIssuerLocation]` is what invokes the Provider Configuration or Authorization Server Metadata endpoint in order to derive the JWK Set Uri.
@@ -223,6 +227,39 @@ If the application doesn't expose a `JwtDecoder` bean, then Spring Boot will exp
And its configuration can be overridden using `jwkSetUri()` or replaced using `decoder()`.
+Or, if you're not using Spring Boot at all, then both of these components - the filter chain and a `JwtDecoder` can be specified in XML.
+
+The filter chain is specified like so:
+
+.Default JWT Configuration
+====
+.Xml
+[source,xml,role="primary"]
+----
+
+
+
+
+
+
+----
+====
+
+And the `JwtDecoder` like so:
+
+.JWT Decoder
+====
+.Xml
+[source,xml,role="primary"]
+----
+
+
+
+----
+====
+
[[oauth2resourceserver-jwt-jwkseturi-dsl]]
==== Using `jwkSetUri()`
@@ -268,6 +305,17 @@ class DirectlyConfiguredJwkSetUri : WebSecurityConfigurerAdapter() {
}
}
----
+
+.Xml
+[source,xml,role="secondary"]
+----
+
+
+
+
+
+
+----
====
Using `jwkSetUri()` takes precedence over any configuration property.
@@ -317,6 +365,17 @@ class DirectlyConfiguredJwtDecoder : WebSecurityConfigurerAdapter() {
}
}
----
+
+.Xml
+[source,xml,role="secondary"]
+----
+
+
+
+
+
+
+----
====
This is handy when deeper configuration, like <>, <>, or <>, is necessary.
@@ -541,6 +600,18 @@ class DirectlyConfiguredJwkSetUri : WebSecurityConfigurerAdapter() {
}
}
----
+
+.Xml
+[source,xml,role="secondary"]
+----
+
+
+
+
+
+
+
+----
====
Or similarly with method security:
@@ -616,6 +687,26 @@ class DirectlyConfiguredJwkSetUri : WebSecurityConfigurerAdapter() {
}
}
----
+
+.Xml
+[source,xml,role="secondary"]
+----
+
+
+
+
+
+
+
+
+
+----
====
which is responsible for converting a `Jwt` into an `Authentication`.
@@ -1070,6 +1161,40 @@ If the application doesn't expose a `OpaqueTokenIntrospector` bean, then Spring
And its configuration can be overridden using `introspectionUri()` and `introspectionClientCredentials()` or replaced using `introspector()`.
+Or, if you're not using Spring Boot at all, then both of these components - the filter chain and a `OpaqueTokenIntrospector` can be specified in XML.
+
+The filter chain is specified like so:
+
+.Default Opaque Token Configuration
+====
+.Xml
+[source,xml,role="primary"]
+----
+
+
+
+
+
+
+----
+====
+
+And the `OpaqueTokenIntrospector` like so:
+
+.Opaque Token Introspector
+====
+.Xml
+[source,xml,role="primary"]
+----
+
+
+
+
+
+----
+====
+
[[oauth2resourceserver-opaque-introspectionuri-dsl]]
==== Using `introspectionUri()`
@@ -1117,6 +1242,17 @@ class DirectlyConfiguredIntrospectionUri : WebSecurityConfigurerAdapter() {
}
}
----
+
+.Xml
+[source,xml,role="secondary"]
+----
+
+
+
+
+
+----
====
Using `introspectionUri()` takes precedence over any configuration property.
@@ -1166,6 +1302,17 @@ class DirectlyConfiguredIntrospector : WebSecurityConfigurerAdapter() {
}
}
----
+
+.Xml
+[source,xml,role="secondary"]
+----
+
+
+
+
+
+
+----
====
This is handy when deeper configuration, like <>, <>, or <>, is necessary.
@@ -1194,7 +1341,11 @@ When this is the case, Resource Server will attempt to coerce these scopes into
This means that to protect an endpoint or method with a scope derived from an Opaque Token, the corresponding expressions should include this prefix:
-```java
+.Authorization Opaque Token Configuration
+====
+.Java
+[source,java,role="primary"]
+----
@EnableWebSecurity
public class MappedAuthorities extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) {
@@ -1207,7 +1358,20 @@ public class MappedAuthorities extends WebSecurityConfigurerAdapter {
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::opaqueToken);
}
}
-```
+----
+
+.Xml
+[source,xml,role="secondary"]
+----
+
+
+
+
+
+
+
+----
+====
Or similarly with method security:
@@ -1450,7 +1614,10 @@ AuthenticationManagerResolver tokenAuthenticationManagerReso
And then specify this `AuthenticationManagerResolver` in the DSL:
-[source,java]
+.Authentication Manager Resolver
+====
+.Java
+[source,java,role="primary"]
----
http
.authorizeRequests(authorize -> authorize
@@ -1461,6 +1628,15 @@ http
);
----
+.Xml
+[source,xml,role="secondary"]
+----
+
+
+
+----
+====
+
[[oauth2resourceserver-multitenancy]]
=== Multi-tenancy
@@ -1478,7 +1654,10 @@ In each case, there are two things that need to be done and trade-offs associate
One way to differentiate tenants is by the issuer claim. Since the issuer claim accompanies signed JWTs, this can be done with the `JwtIssuerAuthenticationManagerResolver`, like so:
-[source,java]
+.Multitenancy Tenant by JWT Claim
+====
+.Java
+[source,java,role="primary"]
----
JwtIssuerAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerAuthenticationManagerResolver
("https://idp.example.org/issuerOne", "https://idp.example.org/issuerTwo");
@@ -1492,6 +1671,25 @@ http
);
----
+.Xml
+[source,xml,role="secondary"]
+----
+
+
+
+
+
+
+
+ https://idp.example.org/issuerOne
+ https://idp.example.org/issuerTwo
+
+
+
+----
+====
+
This is nice because the issuer endpoints are loaded lazily.
In fact, the corresponding `JwtAuthenticationProvider` is instantiated only when the first request with the corresponding issuer is sent.
This allows for an application startup that is independent from those authorization servers being up and available.
@@ -1667,7 +1865,10 @@ This, however, can be customized in a couple of ways.
For example, you may have a need to read the bearer token from a custom header.
To achieve this, you can wire a `HeaderBearerTokenResolver` instance into the DSL, as you can see in the following example:
-[source,java]
+.Custom Bearer Token Header
+====
+.Java
+[source,java,role="primary"]
----
http
.oauth2ResourceServer(oauth2 -> oauth2
@@ -1675,11 +1876,28 @@ http
);
----
+.Xml
+[source,xml,role="secondary"]
+----
+
+
+
+
+
+----
+====
+
==== Reading the Bearer Token from a Form Parameter
Or, you may wish to read the token from a form parameter, which you can do by configuring the `DefaultBearerTokenResolver`, as you can see below:
-[source,java]
+.Form Parameter Bearer Token
+====
+.Java
+[source,java,role="primary"]
----
DefaultBearerTokenResolver resolver = new DefaultBearerTokenResolver();
resolver.setAllowFormEncodedBodyParameter(true);
@@ -1689,6 +1907,20 @@ http
);
----
+.Xml
+[source,xml,role="secondary"]
+----
+
+
+
+
+
+----
+====
+
=== Bearer Token Propagation
Now that you're in possession of a bearer token, it might be handy to pass that to downstream services.