Skip to content

Commit e22bc11

Browse files
douxiaofeng99jzheaux
authored andcommitted
Support JWK Selection Strategy
Closes gh-16170 Signed-off-by: douxiaofeng99 <[email protected]>
1 parent 776eb76 commit e22bc11

File tree

1 file changed

+28
-13
lines changed

1 file changed

+28
-13
lines changed

Diff for: oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtEncoder.java

+28-13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 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.
@@ -46,6 +46,7 @@
4646
import com.nimbusds.jwt.JWTClaimsSet;
4747
import com.nimbusds.jwt.SignedJWT;
4848

49+
import org.springframework.core.convert.converter.Converter;
4950
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
5051
import org.springframework.util.Assert;
5152
import org.springframework.util.CollectionUtils;
@@ -86,6 +87,19 @@ public final class NimbusJwtEncoder implements JwtEncoder {
8687

8788
private final JWKSource<SecurityContext> jwkSource;
8889

90+
private Converter<List<JWK>, JWK> jwkSelector= (jwks)->{
91+
if (jwks.size() > 1) {
92+
throw new JwtEncodingException(String.format(
93+
"Failed to select a key since there are multiple for the signing algorithm [%s]; " +
94+
"please specify a selector in NimbusJwsEncoder#setJwkSelector",jwks.get(0).getAlgorithm()));
95+
}
96+
if (jwks.isEmpty()) {
97+
throw new JwtEncodingException(
98+
String.format(ENCODING_ERROR_MESSAGE_TEMPLATE, "Failed to select a JWK signing key"));
99+
}
100+
return jwks.get(0);
101+
};
102+
89103
/**
90104
* Constructs a {@code NimbusJwtEncoder} using the provided parameters.
91105
* @param jwkSource the {@code com.nimbusds.jose.jwk.source.JWKSource}
@@ -94,6 +108,18 @@ public NimbusJwtEncoder(JWKSource<SecurityContext> jwkSource) {
94108
Assert.notNull(jwkSource, "jwkSource cannot be null");
95109
this.jwkSource = jwkSource;
96110
}
111+
/**
112+
* Use this strategy to reduce the list of matching JWKs down to a since one.
113+
* <p> For example, you can call {@code setJwkSelector(List::getFirst)} in order
114+
* to have this encoder select the first match.
115+
*
116+
* <p> By default, the class with throw an exception if there is more than one result.
117+
* @since 6.5
118+
*/
119+
public void setJwkSelector(Converter<List<JWK>, JWK> jwkSelector) {
120+
if(null!=jwkSelector)
121+
this.jwkSelector = jwkSelector;
122+
}
97123

98124
@Override
99125
public Jwt encode(JwtEncoderParameters parameters) throws JwtEncodingException {
@@ -123,18 +149,7 @@ private JWK selectJwk(JwsHeader headers) {
123149
throw new JwtEncodingException(String.format(ENCODING_ERROR_MESSAGE_TEMPLATE,
124150
"Failed to select a JWK signing key -> " + ex.getMessage()), ex);
125151
}
126-
127-
if (jwks.size() > 1) {
128-
throw new JwtEncodingException(String.format(ENCODING_ERROR_MESSAGE_TEMPLATE,
129-
"Found multiple JWK signing keys for algorithm '" + headers.getAlgorithm().getName() + "'"));
130-
}
131-
132-
if (jwks.isEmpty()) {
133-
throw new JwtEncodingException(
134-
String.format(ENCODING_ERROR_MESSAGE_TEMPLATE, "Failed to select a JWK signing key"));
135-
}
136-
137-
return jwks.get(0);
152+
return this.jwkSelector.convert(jwks);
138153
}
139154

140155
private String serialize(JwsHeader headers, JwtClaimsSet claims, JWK jwk) {

0 commit comments

Comments
 (0)