@@ -261,6 +261,16 @@ public static SecretKeyJwtDecoderBuilder withSecretKey(SecretKey secretKey) {
261261 return new SecretKeyJwtDecoderBuilder (secretKey );
262262 }
263263
264+ /**
265+ * Use the given {@code JWKSource} to create a JwkSourceJwtDecoderBuilder.
266+ * @param jwkSource the JWK Source to use
267+ * @return a {@link JwkSetUriJwtDecoderBuilder} for further configurations
268+ * @since 7.0
269+ */
270+ public static JwkSourceJwtDecoderBuilder withJwkSource (JWKSource <SecurityContext > jwkSource ) {
271+ return new JwkSourceJwtDecoderBuilder (jwkSource );
272+ }
273+
264274 /**
265275 * A builder for creating {@link NimbusJwtDecoder} instances based on a
266276 * <a target="_blank" href="https://tools.ietf.org/html/rfc7517#section-5">JWK Set</a>
@@ -535,6 +545,108 @@ public void close() {
535545
536546 }
537547
548+ /**
549+ * A builder for creating {@link NimbusJwtDecoder} instances based on a
550+ * {@code JWKSource}.
551+ */
552+ public static final class JwkSourceJwtDecoderBuilder {
553+
554+ private static final JOSEObjectTypeVerifier <SecurityContext > NO_TYPE_VERIFIER = (header , context ) -> {
555+ };
556+
557+ private final Function <JWKSource <SecurityContext >, Set <JWSAlgorithm >> defaultAlgorithms = (source ) -> Set
558+ .of (JWSAlgorithm .RS256 );
559+
560+ private final JOSEObjectTypeVerifier <SecurityContext > typeVerifier = NO_TYPE_VERIFIER ;
561+
562+ private final Set <SignatureAlgorithm > signatureAlgorithms = new HashSet <>();
563+
564+ private Consumer <ConfigurableJWTProcessor <SecurityContext >> jwtProcessorCustomizer ;
565+
566+ private final JWKSource <SecurityContext > jwkSource ;
567+
568+ private JwkSourceJwtDecoderBuilder (JWKSource <SecurityContext > jwkSource ) {
569+ Assert .notNull (jwkSource , "jwkSource cannot be null" );
570+ this .jwkSource = jwkSource ;
571+ this .jwtProcessorCustomizer = (processor ) -> {
572+ };
573+ }
574+
575+ /**
576+ * Append the given signing
577+ * <a href="https://tools.ietf.org/html/rfc7515#section-4.1.1" target=
578+ * "_blank">algorithm</a> to the set of algorithms to use.
579+ * @param signatureAlgorithm the algorithm to use
580+ * @return a {@link JwkSourceJwtDecoderBuilder } for further configurations
581+ */
582+ public JwkSourceJwtDecoderBuilder jwsAlgorithm (SignatureAlgorithm signatureAlgorithm ) {
583+ Assert .notNull (signatureAlgorithm , "signatureAlgorithm cannot be null" );
584+ this .signatureAlgorithms .add (signatureAlgorithm );
585+ return this ;
586+ }
587+
588+ /**
589+ * Configure the list of
590+ * <a href="https://tools.ietf.org/html/rfc7515#section-4.1.1" target=
591+ * "_blank">algorithms</a> to use with the given {@link Consumer}.
592+ * @param signatureAlgorithmsConsumer a {@link Consumer} for further configuring
593+ * the algorithm list
594+ * @return a {@link JwkSourceJwtDecoderBuilder } for further configurations
595+ */
596+ public JwkSourceJwtDecoderBuilder jwsAlgorithms (Consumer <Set <SignatureAlgorithm >> signatureAlgorithmsConsumer ) {
597+ Assert .notNull (signatureAlgorithmsConsumer , "signatureAlgorithmsConsumer cannot be null" );
598+ signatureAlgorithmsConsumer .accept (this .signatureAlgorithms );
599+ return this ;
600+ }
601+
602+ /**
603+ * Use the given {@link Consumer} to customize the {@link JWTProcessor
604+ * ConfigurableJWTProcessor} before passing it to the build
605+ * {@link NimbusJwtDecoder}.
606+ * @param jwtProcessorCustomizer the callback used to alter the processor
607+ * @return a {@link JwkSourceJwtDecoderBuilder } for further configurations
608+ * @since 5.4
609+ */
610+ public JwkSourceJwtDecoderBuilder jwtProcessorCustomizer (
611+ Consumer <ConfigurableJWTProcessor <SecurityContext >> jwtProcessorCustomizer ) {
612+ Assert .notNull (jwtProcessorCustomizer , "jwtProcessorCustomizer cannot be null" );
613+ this .jwtProcessorCustomizer = jwtProcessorCustomizer ;
614+ return this ;
615+ }
616+
617+ JWSKeySelector <SecurityContext > jwsKeySelector (JWKSource <SecurityContext > jwkSource ) {
618+ if (this .signatureAlgorithms .isEmpty ()) {
619+ return new JWSVerificationKeySelector <>(this .defaultAlgorithms .apply (jwkSource ), jwkSource );
620+ }
621+ Set <JWSAlgorithm > jwsAlgorithms = new HashSet <>();
622+ for (SignatureAlgorithm signatureAlgorithm : this .signatureAlgorithms ) {
623+ JWSAlgorithm jwsAlgorithm = JWSAlgorithm .parse (signatureAlgorithm .getName ());
624+ jwsAlgorithms .add (jwsAlgorithm );
625+ }
626+ return new JWSVerificationKeySelector <>(jwsAlgorithms , jwkSource );
627+ }
628+
629+ JWTProcessor <SecurityContext > processor () {
630+ ConfigurableJWTProcessor <SecurityContext > jwtProcessor = new DefaultJWTProcessor <>();
631+ jwtProcessor .setJWSTypeVerifier (this .typeVerifier );
632+ jwtProcessor .setJWSKeySelector (jwsKeySelector (this .jwkSource ));
633+ // Spring Security validates the claim set independent from Nimbus
634+ jwtProcessor .setJWTClaimsSetVerifier ((claims , context ) -> {
635+ });
636+ this .jwtProcessorCustomizer .accept (jwtProcessor );
637+ return jwtProcessor ;
638+ }
639+
640+ /**
641+ * Build the configured {@link NimbusJwtDecoder}.
642+ * @return the configured {@link NimbusJwtDecoder}
643+ */
644+ public NimbusJwtDecoder build () {
645+ return new NimbusJwtDecoder (processor ());
646+ }
647+
648+ }
649+
538650 /**
539651 * A builder for creating {@link NimbusJwtDecoder} instances based on a public key.
540652 */
0 commit comments