OAuth 2.0 リソースサーバー JWT

JWT の最小依存関係

ほとんどのリソースサーバーサポートは spring-security-oauth2-resource-server に収集されます。ただし、JWT のデコードと検証のサポートは spring-security-oauth2-jose にあります。つまり、JWT でエンコードされたベアラートークンをサポートするリソースサーバーが機能するためには、両方が必要です。

JWT の最小構成

Spring Boot を使用する場合、アプリケーションをリソースサーバーとして構成することは、2 つの基本的な手順で構成されます。まず、必要な依存関係を含めます。次に、認可サーバーの場所を示します。

認可サーバーの指定

Spring Boot アプリケーションでは、使用する認証サーバーを指定する必要があります。

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: https://idp.example.com/issuer

ここで、idp.example.com/issuer (英語)  は、認証サーバーが発行する JWT トークンの iss クレームに含まれる値です。このリソースサーバーは、このプロパティを使用して、さらに自己構成し、認可サーバーの公開鍵を検出し、その後、受信 JWT を検証します。

issuer-uri プロパティを使用するには、idp.example.com/issuer/.well-known/openid-configuration (英語) idp.example.com/.well-known/openid-configuration/issuer (英語) idp.example.com/.well-known/oauth-authorization-server/issuer (英語)  のいずれかが認可サーバーでサポートされているエンドポイントであることも真である必要があります。このエンドポイントは、プロバイダー構成 (英語) エンドポイントまたは認可サーバーのメタデータ [IETF] (英語) エンドポイントと呼ばれます。

スタートアップの期待

このプロパティとこれらの依存関係を使用すると、ResourceServer は JWT でエンコードされたベアラートークンを検証するように自動的に構成されます。

これは、決定論的な起動プロセスを通じてこれを実現します。

  1. プロバイダー構成または認可サーバーのメタデータエンドポイントにアクセスし、jwks_url プロパティのレスポンスを処理します。

  2. 有効な公開鍵を jwks_url に照会するように検証戦略を構成します。

  3. 検証戦略を構成して、各 JWT の iss クレームを idp.example.com (英語) に対して検証します。

このプロセスの結果、リソースサーバーが正常に起動するには、認可サーバーがリクエストを受信している必要があります。

リソースサーバーが認証サーバーにクエリを実行したときに認証サーバーがダウンしている場合(適切なタイムアウトが指定されている場合)、起動は失敗します。

ランタイムの期待

アプリケーションが起動すると、ResourceServer は Authorization: Bearer ヘッダーを含むすべてのリクエストを処理しようとします。

GET / HTTP/1.1
Authorization: Bearer some-token-value # Resource Server will process this

このスキームが示されている限り、ResourceServer は BearerToken 仕様に従ってリクエストを処理しようとします。

整形式の JWT、リソースサーバーを考えると:

  1. 起動時に jwks_url エンドポイントから取得され、JWT ヘッダーと照合された公開鍵に対して署名を検証します。

  2. JWT の exp と nbf のタイムスタンプと JWT の iss クレームを検証します。

  3. 各スコープを接頭辞 SCOPE_ の権限にマップします。

認可サーバーが新しいキーを利用できるようになると、Spring Security は JWT トークンの検証に使用されるキーを自動的にローテーションします。

デフォルトでは、結果の Authentication#getPrincipal は Spring Security Jwt オブジェクトであり、Authentication#getName は JWT の sub プロパティ(存在する場合)にマップされます。

ここから、次へのジャンプを検討してください。

認可サーバー JWK セット Uri を直接指定する

認可サーバーが構成エンドポイントをサポートしていない場合、またはリソースサーバーが認可サーバーから独立して起動できる必要がある場合は、jwk-set-uri も指定できます。

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: https://idp.example.com
          jwk-set-uri: https://idp.example.com/.well-known/jwks.json

JWK Set uri は標準化されていませんが、通常、認証サーバーのドキュメントに記載されています。

その結果、リソースサーバーは起動時に認証サーバーに ping を実行しません。リソースサーバーが受信 JWT に対する iss クレームを検証するように、引き続き issuer-uri を指定します。

このプロパティは、DSL で直接指定できます。

Boot 自動構成のオーバーライドまたは置換

Spring Boot は、ResourceServer に代わって 2 つの @Bean オブジェクトを生成します。

最初の Bean は、アプリケーションをリソースサーバーとして構成する SecurityWebFilterChain です。spring-security-oauth2-jose を含めると、この SecurityWebFilterChain は次のようになります。

リソースサーバー SecurityWebFilterChain
  • Java

  • Kotlin

@Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
	http
		.authorizeExchange(exchanges -> exchanges
			.anyExchange().authenticated()
		)
		.oauth2ResourceServer(OAuth2ResourceServerSpec::jwt)
	return http.build();
}
@Bean
fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
    return http {
        authorizeExchange {
            authorize(anyExchange, authenticated)
        }
        oauth2ResourceServer {
            jwt { }
        }
    }
}

アプリケーションが SecurityWebFilterChain Bean を公開しない場合、Spring Boot はデフォルトのもの(前のリストに示されている)を公開します。

これを置き換えるには、アプリケーション内で @Bean を公開します。

SecurityWebFilterChain の交換
  • Java

  • Kotlin

import static org.springframework.security.oauth2.core.authorization.OAuth2ReactiveAuthorizationManagers.hasScope;

@Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
	http
		.authorizeExchange(exchanges -> exchanges
			.pathMatchers("/message/**").access(hasScope("message:read"))
			.anyExchange().authenticated()
		)
		.oauth2ResourceServer(oauth2 -> oauth2
			.jwt(withDefaults())
		);
	return http.build();
}
import org.springframework.security.oauth2.core.authorization.OAuth2ReactiveAuthorizationManagers.hasScope

@Bean
fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
    return http {
        authorizeExchange {
            authorize("/message/**", hasScope("message:read"))
            authorize(anyExchange, authenticated)
        }
        oauth2ResourceServer {
            jwt { }
        }
    }
}

上記の構成では、/messages/ で始まる URL に対して message:read のスコープが必要です。

oauth2ResourceServer DSL のメソッドも、自動構成をオーバーライドまたは置換します。

例: Spring Boot が 2 番目に作成する @Bean は、String トークンを Jwt の検証済みインスタンスにデコードする ReactiveJwtDecoder です。

ReactiveJwtDecoder
  • Java

  • Kotlin

@Bean
public ReactiveJwtDecoder jwtDecoder() {
    return ReactiveJwtDecoders.fromIssuerLocation(issuerUri);
}
@Bean
fun jwtDecoder(): ReactiveJwtDecoder {
    return ReactiveJwtDecoders.fromIssuerLocation(issuerUri)
}

ReactiveJwtDecoders#fromIssuerLocation (Javadoc)  を呼び出すと、プロバイダー構成または認可サーバーのメタデータエンドポイントが呼び出され、JWK セット URI が取得されます。アプリケーションが ReactiveJwtDecoder Bean を公開しない場合、Spring Boot は上記のデフォルトのものを公開します。

その構成は、jwkSetUri() を使用してオーバーライドするか、decoder() を使用して置き換えることができます。

jwkSetUri() を使用する

認可サーバーの JWK セット URI を構成プロパティとして構成するか、DSL で提供することができます。

  • Java

  • Kotlin

@Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
	http
		.authorizeExchange(exchanges -> exchanges
			.anyExchange().authenticated()
		)
		.oauth2ResourceServer(oauth2 -> oauth2
			.jwt(jwt -> jwt
				.jwkSetUri("https://idp.example.com/.well-known/jwks.json")
			)
		);
	return http.build();
}
@Bean
fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
    return http {
        authorizeExchange {
            authorize(anyExchange, authenticated)
        }
        oauth2ResourceServer {
            jwt {
                jwkSetUri = "https://idp.example.com/.well-known/jwks.json"
            }
        }
    }
}

jwkSetUri() の使用は、構成プロパティよりも優先されます。

decoder() を使用する

decoder() は、JwtDecoder の Spring Boot 自動構成を完全に置き換えるため、jwkSetUri() よりも強力です。

  • Java

  • Kotlin

@Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
	http
		.authorizeExchange(exchanges -> exchanges
			.anyExchange().authenticated()
		)
		.oauth2ResourceServer(oauth2 -> oauth2
			.jwt(jwt -> jwt
				.decoder(myCustomDecoder())
			)
		);
    return http.build();
}
@Bean
fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
    return http {
        authorizeExchange {
            authorize(anyExchange, authenticated)
        }
        oauth2ResourceServer {
            jwt {
                jwtDecoder = myCustomDecoder()
            }
        }
    }
}

これは、検証など、より詳細な構成が必要な場合に便利です。

ReactiveJwtDecoder の公開 @Bean

代わりに、ReactiveJwtDecoder@Bean を公開すると、decoder() と同じ効果があります: 次のように jwkSetUri で構築できます:

  • Java

  • Kotlin

@Bean
public ReactiveJwtDecoder jwtDecoder() {
    return NimbusReactiveJwtDecoder.withJwkSetUri(jwkSetUri).build();
}
@Bean
fun jwtDecoder(): ReactiveJwtDecoder {
    return NimbusReactiveJwtDecoder.withJwkSetUri(jwkSetUri).build()
}

または、次のように、発行者を使用して、build() が呼び出されたときに NimbusReactiveJwtDecoder に jwkSetUri を検索させることもできます。

  • Java

  • Kotlin

@Bean
public ReactiveJwtDecoder jwtDecoder() {
    return NimbusReactiveJwtDecoder.withIssuerLocation(issuer).build();
}
@Bean
fun jwtDecoder(): ReactiveJwtDecoder {
    return NimbusReactiveJwtDecoder.withIssuerLocation(issuer).build()
}

または、デフォルトで問題がなければ、JwtDecoders を使用することもできます。これは、デコーダーのバリデーターの構成に加えて上記を行います。

  • Java

  • Kotlin

@Bean
public ReactiveJwtDecoder jwtDecoder() {
    return ReactiveJwtDecoders.fromIssuerLocation(issuer);
}
@Bean
fun jwtDecoder(): ReactiveJwtDecoder {
    return ReactiveJwtDecoders.fromIssuerLocation(issuer)
}

信頼できるアルゴリズムの構成

デフォルトでは、NimbusReactiveJwtDecoder、つまりリソースサーバーは、RS256 を使用するトークンのみを信頼および検証します。

この動作は、Spring Boot を使用するか、NimbusJwtDecoder ビルダーを使用してカスタマイズできます。

Spring Boot を使用した信頼できるアルゴリズムのカスタマイズ

アルゴリズムを設定する最も簡単な方法は、プロパティとしてです:

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          jws-algorithms: RS512
          jwk-set-uri: https://idp.example.org/.well-known/jwks.json

Builder を使用した信頼できるアルゴリズムのカスタマイズ

ただし、より強力にするには、NimbusReactiveJwtDecoder に同梱されているビルダーを使用できます。

  • Java

  • Kotlin

@Bean
ReactiveJwtDecoder jwtDecoder() {
    return NimbusReactiveJwtDecoder.withIssuerLocation(this.issuer)
            .jwsAlgorithm(RS512).build();
}
@Bean
fun jwtDecoder(): ReactiveJwtDecoder {
    return NimbusReactiveJwtDecoder.withIssuerLocation(this.issuer)
            .jwsAlgorithm(RS512).build()
}

jwsAlgorithm を複数回呼び出すと、NimbusReactiveJwtDecoder は複数のアルゴリズムを信頼するように構成されます。

  • Java

  • Kotlin

@Bean
ReactiveJwtDecoder jwtDecoder() {
    return NimbusReactiveJwtDecoder.withIssuerLocation(this.issuer)
            .jwsAlgorithm(RS512).jwsAlgorithm(ES512).build();
}
@Bean
fun jwtDecoder(): ReactiveJwtDecoder {
    return NimbusReactiveJwtDecoder.withIssuerLocation(this.issuer)
            .jwsAlgorithm(RS512).jwsAlgorithm(ES512).build()
}

または、jwsAlgorithms を呼び出すこともできます。

  • Java

  • Kotlin

@Bean
ReactiveJwtDecoder jwtDecoder() {
    return NimbusReactiveJwtDecoder.withIssuerLocation(this.jwkSetUri)
            .jwsAlgorithms(algorithms -> {
                    algorithms.add(RS512);
                    algorithms.add(ES512);
            }).build();
}
@Bean
fun jwtDecoder(): ReactiveJwtDecoder {
    return NimbusReactiveJwtDecoder.withIssuerLocation(this.jwkSetUri)
            .jwsAlgorithms {
                it.add(RS512)
                it.add(ES512)
            }
            .build()
}

単一の非対称キーを信頼する

JWK Set エンドポイントを使用してリソースサーバーをバックアップするよりも簡単なのは、RSA 公開鍵をハードコードすることです。公開鍵は、Spring Boot またはビルダーを使用するで提供できます。

Spring Boot 経由

Spring Boot でキーを指定できます。

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          public-key-location: classpath:my-key.pub

または、より高度なルックアップを可能にするために、RsaKeyConversionServicePostProcessor を後処理することができます。

BeanFactoryPostProcessor
  • Java

  • Kotlin

@Bean
BeanFactoryPostProcessor conversionServiceCustomizer() {
    return beanFactory ->
        beanFactory.getBean(RsaKeyConversionServicePostProcessor.class)
                .setResourceLoader(new CustomResourceLoader());
}
@Bean
fun conversionServiceCustomizer(): BeanFactoryPostProcessor {
    return BeanFactoryPostProcessor { beanFactory: ConfigurableListableBeanFactory ->
        beanFactory.getBean<RsaKeyConversionServicePostProcessor>()
                .setResourceLoader(CustomResourceLoader())
    }
}

キーの場所を指定します。

key.location: hfds://my-key.pub

次に、値をオートワイヤーします。

  • Java

  • Kotlin

@Value("${key.location}")
RSAPublicKey key;
@Value("\${key.location}")
val key: RSAPublicKey? = null

ビルダーを使用する

RSAPublicKey を直接接続するには、適切な NimbusReactiveJwtDecoder ビルダーを使用します。

  • Java

  • Kotlin

@Bean
public ReactiveJwtDecoder jwtDecoder() {
    return NimbusReactiveJwtDecoder.withPublicKey(this.key).build();
}
@Bean
fun jwtDecoder(): ReactiveJwtDecoder {
    return NimbusReactiveJwtDecoder.withPublicKey(key).build()
}

単一の対称キーを信頼する

単一の対称鍵を使用することもできます。SecretKey をロードして、適切な NimbusReactiveJwtDecoder ビルダーを使用できます。

  • Java

  • Kotlin

@Bean
public ReactiveJwtDecoder jwtDecoder() {
    return NimbusReactiveJwtDecoder.withSecretKey(this.key).build();
}
@Bean
fun jwtDecoder(): ReactiveJwtDecoder {
    return NimbusReactiveJwtDecoder.withSecretKey(this.key).build()
}

認可の構成

OAuth 2.0 認可サーバーから発行される JWT には、通常、scope 属性または scp 属性のいずれかがあり、付与されたスコープ(または権限)を示します。たとえば、次のようになります。

{ ..., "scope" : "messages contacts"}

この場合、リソースサーバーは、これらのスコープを許可された権限のリストに強制的に入れ、各スコープの前に文字列 SCOPE_ を付けます。

これは、JWT から派生したスコープでエンドポイントまたはメソッドを保護するために、対応する式に次のプレフィックスを含める必要があることを意味します。

  • Java

  • Kotlin

import static org.springframework.security.oauth2.core.authorization.OAuth2ReactiveAuthorizationManagers.hasScope;

@Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
	http
		.authorizeExchange(exchanges -> exchanges
			.mvcMatchers("/contacts/**").access(hasScope("contacts"))
			.mvcMatchers("/messages/**").access(hasScope("messages"))
			.anyExchange().authenticated()
		)
		.oauth2ResourceServer(OAuth2ResourceServerSpec::jwt);
    return http.build();
}
import org.springframework.security.oauth2.core.authorization.OAuth2ReactiveAuthorizationManagers.hasScope

@Bean
fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
    return http {
        authorizeExchange {
            authorize("/contacts/**", hasScope("contacts"))
            authorize("/messages/**", hasScope("messages"))
            authorize(anyExchange, authenticated)
        }
        oauth2ResourceServer {
            jwt { }
        }
    }
}

メソッドセキュリティと同様のことができます。

  • Java

  • Kotlin

@PreAuthorize("hasAuthority('SCOPE_messages')")
public Flux<Message> getMessages(...) {}
@PreAuthorize("hasAuthority('SCOPE_messages')")
fun getMessages(): Flux<Message> { }

権限の手動抽出

ただし、このデフォルトでは不十分な状況がいくつかあります。例: 一部の認証サーバーは scope 属性を使用しません。代わりに、独自のカスタム属性があります。また、リソースサーバーは、属性または属性の構成を内部化された権限に適合させる必要がある場合があります。

このために、DSL は jwtAuthenticationConverter() を公開します:

  • Java

  • Kotlin

@Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
	http
		.authorizeExchange(exchanges -> exchanges
			.anyExchange().authenticated()
		)
		.oauth2ResourceServer(oauth2 -> oauth2
			.jwt(jwt -> jwt
				.jwtAuthenticationConverter(grantedAuthoritiesExtractor())
			)
		);
	return http.build();
}

Converter<Jwt, Mono<AbstractAuthenticationToken>> grantedAuthoritiesExtractor() {
    JwtAuthenticationConverter jwtAuthenticationConverter =
            new JwtAuthenticationConverter();
    jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter
            (new GrantedAuthoritiesExtractor());
    return new ReactiveJwtAuthenticationConverterAdapter(jwtAuthenticationConverter);
}
@Bean
fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
    return http {
        authorizeExchange {
            authorize(anyExchange, authenticated)
        }
        oauth2ResourceServer {
            jwt {
                jwtAuthenticationConverter = grantedAuthoritiesExtractor()
            }
        }
    }
}

fun grantedAuthoritiesExtractor(): Converter<Jwt, Mono<AbstractAuthenticationToken>> {
    val jwtAuthenticationConverter = JwtAuthenticationConverter()
    jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(GrantedAuthoritiesExtractor())
    return ReactiveJwtAuthenticationConverterAdapter(jwtAuthenticationConverter)
}

jwtAuthenticationConverter() は、Jwt を Authentication に変換するロールを果たします。その構成の一部として、Jwt から付与された権限の Collection に移行するための補助コンバーターを提供できます。

その最終的なコンバーターは、次の GrantedAuthoritiesExtractor のようなものになる可能性があります。

  • Java

  • Kotlin

static class GrantedAuthoritiesExtractor
        implements Converter<Jwt, Collection<GrantedAuthority>> {

    public Collection<GrantedAuthority> convert(Jwt jwt) {
        Collection<?> authorities = (Collection<?>)
                jwt.getClaims().getOrDefault("mycustomclaim", Collections.emptyList());

        return authorities.stream()
                .map(Object::toString)
                .map(SimpleGrantedAuthority::new)
                .collect(Collectors.toList());
    }
}
internal class GrantedAuthoritiesExtractor : Converter<Jwt, Collection<GrantedAuthority>> {
    override fun convert(jwt: Jwt): Collection<GrantedAuthority> {
        val authorities: List<Any> = jwt.claims
                .getOrDefault("mycustomclaim", emptyList<Any>()) as List<Any>
        return authorities
                .map { it.toString() }
                .map { SimpleGrantedAuthority(it) }
    }
}

柔軟性を高めるため、DSL はコンバーターを Converter<Jwt, Mono<AbstractAuthenticationToken>> を実装するクラスに完全に置き換えることをサポートしています。

  • Java

  • Kotlin

static class CustomAuthenticationConverter implements Converter<Jwt, Mono<AbstractAuthenticationToken>> {
    public AbstractAuthenticationToken convert(Jwt jwt) {
        return Mono.just(jwt).map(this::doConversion);
    }
}
internal class CustomAuthenticationConverter : Converter<Jwt, Mono<AbstractAuthenticationToken>> {
    override fun convert(jwt: Jwt): Mono<AbstractAuthenticationToken> {
        return Mono.just(jwt).map(this::doConversion)
    }
}

検証の構成

リソースサーバーは、認可サーバーの発行者 URI を示す最小限の Spring Boot 構成を使用して、デフォルトで iss クレームと exp および nbf タイムスタンプクレームを検証します。

検証のニーズをカスタマイズする必要がある状況では、リソースサーバーには 2 つの標準バリデーターが付属しており、カスタム OAuth2TokenValidator インスタンスも受け入れます。

タイムスタンプ検証のカスタマイズ

JWT インスタンスには通常、有効期間があり、ウィンドウの開始は nbf クレームで示され、終了は exp クレームで示されます。

ただし、すべてのサーバーでクロックドリフトが発生する可能性があります。これにより、あるサーバーではトークンの有効期限が切れているように見えますが、別のサーバーでは有効期限が切れていないように見えます。分散システムで協調するサーバーの数が増えるため、これにより実装の胸焼けが発生する可能性があります。

リソースサーバーは JwtTimestampValidator を使用してトークンの有効性ウィンドウを検証し、clockSkew を使用してトークンを構成して、クロックドリフトの問題を軽減できます。

  • Java

  • Kotlin

@Bean
ReactiveJwtDecoder jwtDecoder() {
     NimbusReactiveJwtDecoder jwtDecoder = (NimbusReactiveJwtDecoder)
             ReactiveJwtDecoders.fromIssuerLocation(issuerUri);

     OAuth2TokenValidator<Jwt> withClockSkew = new DelegatingOAuth2TokenValidator<>(
            new JwtTimestampValidator(Duration.ofSeconds(60)),
            new IssuerValidator(issuerUri));

     jwtDecoder.setJwtValidator(withClockSkew);

     return jwtDecoder;
}
@Bean
fun jwtDecoder(): ReactiveJwtDecoder {
    val jwtDecoder = ReactiveJwtDecoders.fromIssuerLocation(issuerUri) as NimbusReactiveJwtDecoder
    val withClockSkew: OAuth2TokenValidator<Jwt> = DelegatingOAuth2TokenValidator(
            JwtTimestampValidator(Duration.ofSeconds(60)),
            JwtIssuerValidator(issuerUri))
    jwtDecoder.setJwtValidator(withClockSkew)
    return jwtDecoder
}

デフォルトでは、ResourceServer は 60 秒のクロックスキューを構成します。

カスタム検証ツールの構成

OAuth2TokenValidator API を使用して、aud クレームのチェックを追加できます。

  • Java

  • Kotlin

public class AudienceValidator implements OAuth2TokenValidator<Jwt> {
    OAuth2Error error = new OAuth2Error("invalid_token", "The required audience is missing", null);

    public OAuth2TokenValidatorResult validate(Jwt jwt) {
        if (jwt.getAudience().contains("messaging")) {
            return OAuth2TokenValidatorResult.success();
        } else {
            return OAuth2TokenValidatorResult.failure(error);
        }
    }
}
class AudienceValidator : OAuth2TokenValidator<Jwt> {
    var error: OAuth2Error = OAuth2Error("invalid_token", "The required audience is missing", null)
    override fun validate(jwt: Jwt): OAuth2TokenValidatorResult {
        return if (jwt.audience.contains("messaging")) {
            OAuth2TokenValidatorResult.success()
        } else {
            OAuth2TokenValidatorResult.failure(error)
        }
    }
}

次に、リソースサーバーに追加するために、ReactiveJwtDecoder インスタンスを指定できます。

  • Java

  • Kotlin

@Bean
ReactiveJwtDecoder jwtDecoder() {
    NimbusReactiveJwtDecoder jwtDecoder = (NimbusReactiveJwtDecoder)
            ReactiveJwtDecoders.fromIssuerLocation(issuerUri);

    OAuth2TokenValidator<Jwt> audienceValidator = new AudienceValidator();
    OAuth2TokenValidator<Jwt> withIssuer = JwtValidators.createDefaultWithIssuer(issuerUri);
    OAuth2TokenValidator<Jwt> withAudience = new DelegatingOAuth2TokenValidator<>(withIssuer, audienceValidator);

    jwtDecoder.setJwtValidator(withAudience);

    return jwtDecoder;
}
@Bean
fun jwtDecoder(): ReactiveJwtDecoder {
    val jwtDecoder = ReactiveJwtDecoders.fromIssuerLocation(issuerUri) as NimbusReactiveJwtDecoder
    val audienceValidator: OAuth2TokenValidator<Jwt> = AudienceValidator()
    val withIssuer: OAuth2TokenValidator<Jwt> = JwtValidators.createDefaultWithIssuer(issuerUri)
    val withAudience: OAuth2TokenValidator<Jwt> = DelegatingOAuth2TokenValidator(withIssuer, audienceValidator)
    jwtDecoder.setJwtValidator(withAudience)
    return jwtDecoder
}