1
0
mirror of synced 2026-08-05 01:36:56 +00:00

Add Documentation for ExpressionJwtGrantedAuthoritiesConverter

Closes gh-18300
This commit is contained in:
Josh Cummings
2026-02-10 09:10:23 -07:00
parent 6b028cfe8e
commit 688b6ca733
3 changed files with 82 additions and 0 deletions
@@ -961,7 +961,11 @@ By default, Spring Security will wire the `JwtAuthenticationProvider` with a def
As part of configuring a `JwtAuthenticationConverter`, you can supply a subsidiary converter to go from `Jwt` to a `Collection` of granted authorities.
[[jwt-granted-authorities-custom-claim-name]]
==== Using a Custom Claim Name
Let's say that your authorization server communicates authorities in a custom claim called `authorities`.
In that case, you can configure the claim that <<oauth2resourceserver-jwt-architecture-jwtauthenticationconverter,`JwtAuthenticationConverter`>> should inspect, like so:
.Authorities Claim Configuration
@@ -1022,6 +1026,9 @@ Xml::
----
======
[[jwt-granted-authorities-custom-scope-prefix]]
==== Using a Custom Scope Prefix
You can also configure the authority prefix to be different as well.
Instead of prefixing each authority with `SCOPE_`, you can change it to `ROLE_` like so:
@@ -1153,6 +1160,17 @@ class CustomAuthenticationConverterConfig {
----
======
[[jwt-granted-authorities-spel-expression]]
==== Using a SpEL Expression
In circumstances where the location of scopes is nested or complex in some other way, you can use `ExpressionJwtGrantedAuthoritiesConverter` with a SpEL expression to extract the scopes.
For example, if your JWT has a claim called `nested` and, inside of that, it has a claim called `scopes`, you can do:
include-code::./ExpressionJwtGrantedAuthoritiesConverterTests[tag=spel-expression,indent=0]
The SpEL expression result should be a `Collection`.
[[oauth2resourceserver-jwt-validation]]
== Configuring Validation
@@ -0,0 +1,36 @@
package org.springframework.security.docs.servlet.oauth2.resourceserver.jwtgrantedauthoritiesspelexpression;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import org.junit.jupiter.api.Test;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.TestJwts;
import org.springframework.security.oauth2.server.resource.authentication.ExpressionJwtGrantedAuthoritiesConverter;
import static org.assertj.core.api.Assertions.assertThat;
class ExpressionJwtGrantedAuthoritiesConverterTests {
@Test
public void convertWhenTokenHasCustomClaimNameExpressionThenCustomClaimNameAttributeIsTranslatedToAuthorities() {
// @formatter:off
Jwt jwt = TestJwts.jwt()
.claim("nested", Collections.singletonMap("scopes", Arrays.asList("read", "write")))
.build();
// @formatter:on
// tag::spel-expression[]
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("[nested][scopes]");
ExpressionJwtGrantedAuthoritiesConverter converter = new ExpressionJwtGrantedAuthoritiesConverter(expression);
Collection<GrantedAuthority> authorities = converter.convert(jwt);
// end::spel-expression[]
assertThat(authorities).extracting(GrantedAuthority::getAuthority)
.containsExactly("SCOPE_read", "SCOPE_write");
}
}
@@ -0,0 +1,28 @@
package org.springframework.security.kt.docs.servlet.oauth2.resourceserver.jwtgrantedauthoritiesspelexpression
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.tuple
import org.junit.jupiter.api.Test
import org.springframework.expression.spel.standard.SpelExpressionParser
import org.springframework.security.core.GrantedAuthority
import org.springframework.security.oauth2.jwt.TestJwts
import org.springframework.security.oauth2.server.resource.authentication.ExpressionJwtGrantedAuthoritiesConverter
class ExpressionJwtGrantedAuthoritiesConverterTests {
@Test
fun convertWhenTokenHasCustomClaimNameExpressionThenCustomClaimNameAttributeIsTranslatedToAuthorities() {
// @formatter:off
val jwt = TestJwts.jwt()
.claim("nested", mapOf("scopes" to listOf("read", "write")))
.build()
// @formatter:on
// tag::spel-expression[]
val parser = SpelExpressionParser()
val expression = parser.parseExpression("[nested][scopes]")
val converter = ExpressionJwtGrantedAuthoritiesConverter(expression)
val authorities = converter.convert(jwt)
// end::spel-expression[]
assertThat(authorities).extracting(GrantedAuthority::getAuthority)
.containsExactly(tuple("SCOPE_read"), tuple("SCOPE_write"))
}
}