Skip to content

Commit eda2fe9

Browse files
committed
support custom OAuth2AuthenticatedPrincipal in Jwt-based authentication flow (spring-projects#6237)
Signed-off-by: Andrey Litvitski <[email protected]>
1 parent 5517d8f commit eda2fe9

File tree

3 files changed

+58
-5
lines changed

3 files changed

+58
-5
lines changed

oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationConverter.java

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
2121
import org.springframework.core.convert.converter.Converter;
2222
import org.springframework.security.authentication.AbstractAuthenticationToken;
2323
import org.springframework.security.core.GrantedAuthority;
24+
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
2425
import org.springframework.security.oauth2.jwt.Jwt;
2526
import org.springframework.security.oauth2.jwt.JwtClaimNames;
2627
import org.springframework.util.Assert;
@@ -30,10 +31,12 @@
3031
* @author Josh Cummings
3132
* @author Evgeniy Cheban
3233
* @author Olivier Antoine
34+
* @author Andrey Litvitski
3335
* @since 5.1
3436
*/
3537
public class JwtAuthenticationConverter implements Converter<Jwt, AbstractAuthenticationToken> {
3638

39+
private Converter<Jwt, OAuth2AuthenticatedPrincipal> jwtPrincipalConverter;
3740
private Converter<Jwt, Collection<GrantedAuthority>> jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
3841

3942
private String principalClaimName = JwtClaimNames.SUB;
@@ -42,8 +45,26 @@ public class JwtAuthenticationConverter implements Converter<Jwt, AbstractAuthen
4245
public final AbstractAuthenticationToken convert(Jwt jwt) {
4346
Collection<GrantedAuthority> authorities = this.jwtGrantedAuthoritiesConverter.convert(jwt);
4447

45-
String principalClaimValue = jwt.getClaimAsString(this.principalClaimName);
46-
return new JwtAuthenticationToken(jwt, authorities, principalClaimValue);
48+
if (this.jwtPrincipalConverter == null) {
49+
String principalClaimValue = jwt.getClaimAsString(this.principalClaimName);
50+
return new JwtAuthenticationToken(jwt, authorities, principalClaimValue);
51+
} else {
52+
OAuth2AuthenticatedPrincipal principal = this.jwtPrincipalConverter.convert(jwt);
53+
authorities.addAll(principal.getAuthorities());
54+
return new JwtAuthenticationToken(jwt, principal, authorities);
55+
}
56+
}
57+
58+
/**
59+
* Sets the {@link Converter Converter&lt;Jwt, Collection&lt;OAuth2AuthenticatedPrincipal&gt;&gt;}
60+
* to use.
61+
* @param jwtPrincipalConverter The converter
62+
* @since 6.5.0
63+
*/
64+
public void setJwtPrincipalConverter(
65+
Converter<Jwt, OAuth2AuthenticatedPrincipal> jwtPrincipalConverter) {
66+
Assert.notNull(jwtPrincipalConverter, "jwtPrincipalConverter cannot be null");
67+
this.jwtPrincipalConverter = jwtPrincipalConverter;
4768
}
4869

4970
/**

oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationToken.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
1919
import java.util.Collection;
2020
import java.util.Map;
2121

22+
import org.springframework.security.core.AuthenticatedPrincipal;
2223
import org.springframework.security.core.GrantedAuthority;
2324
import org.springframework.security.core.SpringSecurityCoreVersion;
2425
import org.springframework.security.core.Transient;
@@ -29,6 +30,7 @@
2930
* {@link Jwt} {@code Authentication}.
3031
*
3132
* @author Joe Grandja
33+
* @author Andrey Litvitski
3234
* @since 5.1
3335
* @see AbstractOAuth2TokenAuthenticationToken
3436
* @see Jwt
@@ -72,6 +74,22 @@ public JwtAuthenticationToken(Jwt jwt, Collection<? extends GrantedAuthority> au
7274
this.name = name;
7375
}
7476

77+
/**
78+
* Constructs a {@code JwtAuthenticationToken} using the provided parameters.
79+
* @param jwt the JWT
80+
* @param principal the principal
81+
* @param authorities the authorities assigned to the JWT
82+
*/
83+
public JwtAuthenticationToken(Jwt jwt, Object principal, Collection<? extends GrantedAuthority> authorities) {
84+
super(jwt, principal, jwt, authorities);
85+
this.setAuthenticated(true);
86+
if (principal instanceof AuthenticatedPrincipal) {
87+
this.name = ((AuthenticatedPrincipal) principal).getName();
88+
} else {
89+
this.name = jwt.getSubject();
90+
}
91+
}
92+
7593
@Override
7694
public Map<String, Object> getTokenAttributes() {
7795
return this.getToken().getClaims();

oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtBearerTokenAuthenticationConverter.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -26,6 +26,7 @@
2626
import org.springframework.security.oauth2.core.OAuth2AccessToken;
2727
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
2828
import org.springframework.security.oauth2.jwt.Jwt;
29+
import org.springframework.util.Assert;
2930

3031
/**
3132
* A {@link Converter} that takes a {@link Jwt} and converts it into a
@@ -41,6 +42,7 @@
4142
* {@link BearerTokenAuthentication}.
4243
*
4344
* @author Josh Cummings
45+
* @author Andrey Litvitski
4446
* @since 5.2
4547
*/
4648
public final class JwtBearerTokenAuthenticationConverter implements Converter<Jwt, AbstractAuthenticationToken> {
@@ -58,4 +60,16 @@ public AbstractAuthenticationToken convert(Jwt jwt) {
5860
return new BearerTokenAuthentication(principal, accessToken, authorities);
5961
}
6062

63+
/**
64+
* Sets the {@link Converter Converter&lt;Jwt, Collection&lt;OAuth2AuthenticatedPrincipal&gt;&gt;}
65+
* to use.
66+
* @param jwtPrincipalConverter The converter
67+
* @since 6.5.0
68+
*/
69+
public void setJwtPrincipalConverter(
70+
Converter<Jwt, OAuth2AuthenticatedPrincipal> jwtPrincipalConverter) {
71+
Assert.notNull(jwtPrincipalConverter, "jwtPrincipalConverter cannot be null");
72+
this.jwtAuthenticationConverter.setJwtPrincipalConverter(jwtPrincipalConverter);
73+
}
74+
6175
}

0 commit comments

Comments
 (0)