Skip to content

Commit 688b6ca

Browse files
committed
Add Documentation for ExpressionJwtGrantedAuthoritiesConverter
Closes gh-18300
1 parent 6b028cf commit 688b6ca

3 files changed

Lines changed: 82 additions & 0 deletions

File tree

docs/modules/ROOT/pages/servlet/oauth2/resource-server/jwt.adoc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -961,7 +961,11 @@ By default, Spring Security will wire the `JwtAuthenticationProvider` with a def
961961

962962
As part of configuring a `JwtAuthenticationConverter`, you can supply a subsidiary converter to go from `Jwt` to a `Collection` of granted authorities.
963963

964+
[[jwt-granted-authorities-custom-claim-name]]
965+
==== Using a Custom Claim Name
966+
964967
Let's say that your authorization server communicates authorities in a custom claim called `authorities`.
968+
965969
In that case, you can configure the claim that <<oauth2resourceserver-jwt-architecture-jwtauthenticationconverter,`JwtAuthenticationConverter`>> should inspect, like so:
966970

967971
.Authorities Claim Configuration
@@ -1022,6 +1026,9 @@ Xml::
10221026
----
10231027
======
10241028

1029+
[[jwt-granted-authorities-custom-scope-prefix]]
1030+
==== Using a Custom Scope Prefix
1031+
10251032
You can also configure the authority prefix to be different as well.
10261033
Instead of prefixing each authority with `SCOPE_`, you can change it to `ROLE_` like so:
10271034

@@ -1153,6 +1160,17 @@ class CustomAuthenticationConverterConfig {
11531160
----
11541161
======
11551162

1163+
[[jwt-granted-authorities-spel-expression]]
1164+
==== Using a SpEL Expression
1165+
1166+
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.
1167+
1168+
For example, if your JWT has a claim called `nested` and, inside of that, it has a claim called `scopes`, you can do:
1169+
1170+
include-code::./ExpressionJwtGrantedAuthoritiesConverterTests[tag=spel-expression,indent=0]
1171+
1172+
The SpEL expression result should be a `Collection`.
1173+
11561174
[[oauth2resourceserver-jwt-validation]]
11571175
== Configuring Validation
11581176

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package org.springframework.security.docs.servlet.oauth2.resourceserver.jwtgrantedauthoritiesspelexpression;
2+
3+
import java.util.Arrays;
4+
import java.util.Collection;
5+
import java.util.Collections;
6+
7+
import org.junit.jupiter.api.Test;
8+
9+
import org.springframework.expression.Expression;
10+
import org.springframework.expression.spel.standard.SpelExpressionParser;
11+
import org.springframework.security.core.GrantedAuthority;
12+
import org.springframework.security.oauth2.jwt.Jwt;
13+
import org.springframework.security.oauth2.jwt.TestJwts;
14+
import org.springframework.security.oauth2.server.resource.authentication.ExpressionJwtGrantedAuthoritiesConverter;
15+
16+
import static org.assertj.core.api.Assertions.assertThat;
17+
18+
class ExpressionJwtGrantedAuthoritiesConverterTests {
19+
20+
@Test
21+
public void convertWhenTokenHasCustomClaimNameExpressionThenCustomClaimNameAttributeIsTranslatedToAuthorities() {
22+
// @formatter:off
23+
Jwt jwt = TestJwts.jwt()
24+
.claim("nested", Collections.singletonMap("scopes", Arrays.asList("read", "write")))
25+
.build();
26+
// @formatter:on
27+
// tag::spel-expression[]
28+
SpelExpressionParser parser = new SpelExpressionParser();
29+
Expression expression = parser.parseExpression("[nested][scopes]");
30+
ExpressionJwtGrantedAuthoritiesConverter converter = new ExpressionJwtGrantedAuthoritiesConverter(expression);
31+
Collection<GrantedAuthority> authorities = converter.convert(jwt);
32+
// end::spel-expression[]
33+
assertThat(authorities).extracting(GrantedAuthority::getAuthority)
34+
.containsExactly("SCOPE_read", "SCOPE_write");
35+
}
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package org.springframework.security.kt.docs.servlet.oauth2.resourceserver.jwtgrantedauthoritiesspelexpression
2+
3+
import org.assertj.core.api.Assertions.assertThat
4+
import org.assertj.core.api.Assertions.tuple
5+
import org.junit.jupiter.api.Test
6+
import org.springframework.expression.spel.standard.SpelExpressionParser
7+
import org.springframework.security.core.GrantedAuthority
8+
import org.springframework.security.oauth2.jwt.TestJwts
9+
import org.springframework.security.oauth2.server.resource.authentication.ExpressionJwtGrantedAuthoritiesConverter
10+
11+
class ExpressionJwtGrantedAuthoritiesConverterTests {
12+
@Test
13+
fun convertWhenTokenHasCustomClaimNameExpressionThenCustomClaimNameAttributeIsTranslatedToAuthorities() {
14+
// @formatter:off
15+
val jwt = TestJwts.jwt()
16+
.claim("nested", mapOf("scopes" to listOf("read", "write")))
17+
.build()
18+
// @formatter:on
19+
// tag::spel-expression[]
20+
val parser = SpelExpressionParser()
21+
val expression = parser.parseExpression("[nested][scopes]")
22+
val converter = ExpressionJwtGrantedAuthoritiesConverter(expression)
23+
val authorities = converter.convert(jwt)
24+
// end::spel-expression[]
25+
assertThat(authorities).extracting(GrantedAuthority::getAuthority)
26+
.containsExactly(tuple("SCOPE_read"), tuple("SCOPE_write"))
27+
}
28+
}

0 commit comments

Comments
 (0)