parent
b91668a34d
commit
3a9ee46719
|
@ -89,7 +89,7 @@ At this point, the OAuth Client retrieves your email address and basic profile i
|
||||||
== Using OpenID Provider Configuration
|
== Using OpenID Provider Configuration
|
||||||
|
|
||||||
For well known providers, Spring Security provides the necessary defaults for the OAuth Authorization Provider's configuration.
|
For well known providers, Spring Security provides the necessary defaults for the OAuth Authorization Provider's configuration.
|
||||||
If you are working with your own Authorization Provider that supports https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[OpenID Provider Configuration], you may use the https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationResponse[OpenID Provider Configuration Response] the issuer-uri can be used to configure the application.
|
If you are working with your own Authorization Provider that supports https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[OpenID Provider Configuration] or https://tools.ietf.org/html/rfc8414#section-3[Authorization Server Metadata], the https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationResponse[OpenID Provider Configuration Response]'s `issuer-uri` can be used to configure the application.
|
||||||
|
|
||||||
[source,yml]
|
[source,yml]
|
||||||
----
|
----
|
||||||
|
@ -106,7 +106,11 @@ spring:
|
||||||
client-secret: 6cea952f-10d0-4d00-ac79-cc865820dc2c
|
client-secret: 6cea952f-10d0-4d00-ac79-cc865820dc2c
|
||||||
----
|
----
|
||||||
|
|
||||||
The `issuer-uri` instructs Spring Security to leverage the endpoint at `https://idp.example.com/auth/realms/demo/.well-known/openid-configuration` to discover the configuration.
|
The `issuer-uri` instructs Spring Security to query in series the endpoints `https://idp.example.com/auth/realms/demo/.well-known/openid-configuration`, `https://idp.example.com/.well-known/openid-configuration/auth/realms/demo`, or `https://idp.example.com/.well-known/oauth-authorization-server/auth/realms/demo` to discover the configuration.
|
||||||
|
|
||||||
|
[NOTE]
|
||||||
|
Spring Security will query the endpoints one at a time, stopping at the first that gives a 200 response.
|
||||||
|
|
||||||
The `client-id` and `client-secret` are linked to the provider because `keycloak` is used for both the provider and the registration.
|
The `client-id` and `client-secret` are linked to the provider because `keycloak` is used for both the provider and the registration.
|
||||||
|
|
||||||
|
|
||||||
|
@ -120,7 +124,7 @@ A minimal OAuth2 Login configuration is shown below:
|
||||||
@Bean
|
@Bean
|
||||||
ReactiveClientRegistrationRepository clientRegistrations() {
|
ReactiveClientRegistrationRepository clientRegistrations() {
|
||||||
ClientRegistration clientRegistration = ClientRegistrations
|
ClientRegistration clientRegistration = ClientRegistrations
|
||||||
.fromOidcIssuerLocation("https://idp.example.com/auth/realms/demo")
|
.fromIssuerLocation("https://idp.example.com/auth/realms/demo")
|
||||||
.clientId("spring-security")
|
.clientId("spring-security")
|
||||||
.clientSecret("6cea952f-10d0-4d00-ac79-cc865820dc2c")
|
.clientSecret("6cea952f-10d0-4d00-ac79-cc865820dc2c")
|
||||||
.build();
|
.build();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[[webflux-oauth2-resource-server]]
|
[[webflux-oauth2-resource-server]]
|
||||||
= OAuth2 Resource Server
|
= OAuth 2.0 Resource Server
|
||||||
|
|
||||||
Spring Security supports protecting endpoints using two forms of OAuth 2.0 https://tools.ietf.org/html/rfc6750.html[Bearer Tokens]:
|
Spring Security supports protecting endpoints using two forms of OAuth 2.0 https://tools.ietf.org/html/rfc6750.html[Bearer Tokens]:
|
||||||
|
|
||||||
|
@ -36,15 +36,15 @@ spring:
|
||||||
oauth2:
|
oauth2:
|
||||||
resourceserver:
|
resourceserver:
|
||||||
jwt:
|
jwt:
|
||||||
issuer-uri: https://idp.example.com
|
issuer-uri: https://idp.example.com/issuer
|
||||||
----
|
----
|
||||||
|
|
||||||
Where `https://idp.example.com` is the value contained in the `iss` claim for JWT tokens that the authorization server will issue.
|
Where `https://idp.example.com/issuer` is the value contained in the `iss` claim for JWT tokens that the authorization server will issue.
|
||||||
Resource Server will use this property to further self-configure, discover the authorization server's public keys, and subsequently validate incoming JWTs.
|
Resource Server will use this property to further self-configure, discover the authorization server's public keys, and subsequently validate incoming JWTs.
|
||||||
|
|
||||||
[NOTE]
|
[NOTE]
|
||||||
To use the `issuer-uri` property, it must also be true that `https://idp.example.com/.well-known/openid-configuration` is a supported endpoint for the authorization server.
|
To use the `issuer-uri` property, it must also be true that one of `https://idp.example.com/issuer/.well-known/openid-configuration`, `https://idp.example.com/.well-known/openid-configuration/issuer`, or `https://idp.example.com/.well-known/oauth-authorization-server/issuer` is a supported endpoint for the authorization server.
|
||||||
This endpoint is referred to as a https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[Provider Configuration] endpoint.
|
This endpoint is referred to as a https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[Provider Configuration] endpoint or a https://tools.ietf.org/html/rfc8414#section-3[Authorization Server Metadata] endpoint.
|
||||||
|
|
||||||
And that's it!
|
And that's it!
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ When this property and these dependencies are used, Resource Server will automat
|
||||||
|
|
||||||
It achieves this through a deterministic startup process:
|
It achieves this through a deterministic startup process:
|
||||||
|
|
||||||
1. Hit the Provider Configuration endpoint, `https://idp.example.com/.well-known/openid-configuration`, processing the response for the `jwks_url` property
|
1. Hit the Provider Configuration or Authorization Server Metadata endpoint, processing the response for the `jwks_url` property
|
||||||
2. Configure the validation strategy to query `jwks_url` for valid public keys
|
2. Configure the validation strategy to query `jwks_url` for valid public keys
|
||||||
3. Configure the validation strategy to validate each JWTs `iss` claim against `https://idp.example.com`.
|
3. Configure the validation strategy to validate each JWTs `iss` claim against `https://idp.example.com`.
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ From here, consider jumping to:
|
||||||
[[webflux-oauth2resourceserver-jwt-jwkseturi]]
|
[[webflux-oauth2resourceserver-jwt-jwkseturi]]
|
||||||
=== Specifying the Authorization Server JWK Set Uri Directly
|
=== Specifying the Authorization Server JWK Set Uri Directly
|
||||||
|
|
||||||
If the authorization server doesn't support the Provider Configuration endpoint, or if Resource Server must be able to start up independently from the authorization server, then `issuer-uri` can be exchanged for `jwk-set-uri`:
|
If the authorization server doesn't support any configuration endpoints, or if Resource Server must be able to start up independently from the authorization server, then the `jwk-set-uri` can be supplied as well:
|
||||||
|
|
||||||
[source,yaml]
|
[source,yaml]
|
||||||
----
|
----
|
||||||
|
@ -104,6 +104,7 @@ spring:
|
||||||
oauth2:
|
oauth2:
|
||||||
resourceserver:
|
resourceserver:
|
||||||
jwt:
|
jwt:
|
||||||
|
issuer-uri: https://idp.example.com
|
||||||
jwk-set-uri: https://idp.example.com/.well-known/jwks.json
|
jwk-set-uri: https://idp.example.com/.well-known/jwks.json
|
||||||
----
|
----
|
||||||
|
|
||||||
|
@ -111,7 +112,7 @@ spring:
|
||||||
The JWK Set uri is not standardized, but can typically be found in the authorization server's documentation
|
The JWK Set uri is not standardized, but can typically be found in the authorization server's documentation
|
||||||
|
|
||||||
Consequently, Resource Server will not ping the authorization server at startup.
|
Consequently, Resource Server will not ping the authorization server at startup.
|
||||||
However, it will also no longer validate the `iss` claim in the JWT (since Resource Server no longer knows what the issuer value should be).
|
We still specify the `issuer-uri` so that Resource Server still validates the `iss` claim on incoming JWTs.
|
||||||
|
|
||||||
[NOTE]
|
[NOTE]
|
||||||
This property can also be supplied directly on the <<webflux-oauth2resourceserver-jwt-jwkseturi-dsl,DSL>>.
|
This property can also be supplied directly on the <<webflux-oauth2resourceserver-jwt-jwkseturi-dsl,DSL>>.
|
||||||
|
@ -169,10 +170,12 @@ For example, the second `@Bean` Spring Boot creates is a `ReactiveJwtDecoder`, w
|
||||||
----
|
----
|
||||||
@Bean
|
@Bean
|
||||||
public ReactiveJwtDecoder jwtDecoder() {
|
public ReactiveJwtDecoder jwtDecoder() {
|
||||||
return ReactiveJwtDecoders.fromOidcIssuerLocation(issuerUri);
|
return ReactiveJwtDecoders.fromIssuerLocation(issuerUri);
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
[NOTE]
|
||||||
|
Calling `{security-api-url}org/springframework/security/oauth2/jwt/ReactiveJwtDecoders.html#fromIssuerLocation-java.lang.String-[ReactiveJwtDecoders#fromIssuerLocation]` is what invokes the Provider Configuration or Authorization Server Metadata endpoint in order to derive the JWK Set Uri.
|
||||||
If the application doesn't expose a `ReactiveJwtDecoder` bean, then Spring Boot will expose the above default one.
|
If the application doesn't expose a `ReactiveJwtDecoder` bean, then Spring Boot will expose the above default one.
|
||||||
|
|
||||||
And its configuration can be overridden using `jwkSetUri()` or replaced using `decoder()`.
|
And its configuration can be overridden using `jwkSetUri()` or replaced using `decoder()`.
|
||||||
|
@ -494,7 +497,7 @@ Resource Server uses `JwtTimestampValidator` to verify a token's validity window
|
||||||
@Bean
|
@Bean
|
||||||
ReactiveJwtDecoder jwtDecoder() {
|
ReactiveJwtDecoder jwtDecoder() {
|
||||||
NimbusReactiveJwtDecoder jwtDecoder = (NimbusReactiveJwtDecoder)
|
NimbusReactiveJwtDecoder jwtDecoder = (NimbusReactiveJwtDecoder)
|
||||||
ReactiveJwtDecoders.fromOidcIssuerLocation(issuerUri);
|
ReactiveJwtDecoders.fromIssuerLocation(issuerUri);
|
||||||
|
|
||||||
OAuth2TokenValidator<Jwt> withClockSkew = new DelegatingOAuth2TokenValidator<>(
|
OAuth2TokenValidator<Jwt> withClockSkew = new DelegatingOAuth2TokenValidator<>(
|
||||||
new JwtTimestampValidator(Duration.ofSeconds(60)),
|
new JwtTimestampValidator(Duration.ofSeconds(60)),
|
||||||
|
@ -536,7 +539,7 @@ Then, to add into a resource server, it's a matter of specifying the `ReactiveJw
|
||||||
@Bean
|
@Bean
|
||||||
ReactiveJwtDecoder jwtDecoder() {
|
ReactiveJwtDecoder jwtDecoder() {
|
||||||
NimbusReactiveJwtDecoder jwtDecoder = (NimbusReactiveJwtDecoder)
|
NimbusReactiveJwtDecoder jwtDecoder = (NimbusReactiveJwtDecoder)
|
||||||
ReactiveJwtDecoders.fromOidcIssuerLocation(issuerUri);
|
ReactiveJwtDecoders.fromIssuerLocation(issuerUri);
|
||||||
|
|
||||||
OAuth2TokenValidator<Jwt> audienceValidator = new AudienceValidator();
|
OAuth2TokenValidator<Jwt> audienceValidator = new AudienceValidator();
|
||||||
OAuth2TokenValidator<Jwt> withIssuer = JwtValidators.createDefaultWithIssuer(issuerUri);
|
OAuth2TokenValidator<Jwt> withIssuer = JwtValidators.createDefaultWithIssuer(issuerUri);
|
||||||
|
|
|
@ -75,6 +75,7 @@ The following sections will go into more detail on the core components used by O
|
||||||
|
|
||||||
* <<oauth2Client-core-interface-class>>
|
* <<oauth2Client-core-interface-class>>
|
||||||
** <<oauth2Client-client-registration, ClientRegistration>>
|
** <<oauth2Client-client-registration, ClientRegistration>>
|
||||||
|
** <<oauth2Client-client-registrations, ClientRegistrations>>
|
||||||
** <<oauth2Client-client-registration-repo, ClientRegistrationRepository>>
|
** <<oauth2Client-client-registration-repo, ClientRegistrationRepository>>
|
||||||
** <<oauth2Client-authorized-client, OAuth2AuthorizedClient>>
|
** <<oauth2Client-authorized-client, OAuth2AuthorizedClient>>
|
||||||
** <<oauth2Client-authorized-repo-service, OAuth2AuthorizedClientRepository / OAuth2AuthorizedClientService>>
|
** <<oauth2Client-authorized-repo-service, OAuth2AuthorizedClientRepository / OAuth2AuthorizedClientService>>
|
||||||
|
@ -153,6 +154,26 @@ The name may be used in certain scenarios, such as when displaying the name of t
|
||||||
The supported values are *header*, *form* and *query*.
|
The supported values are *header*, *form* and *query*.
|
||||||
<15> `userNameAttributeName`: The name of the attribute returned in the UserInfo Response that references the Name or Identifier of the end-user.
|
<15> `userNameAttributeName`: The name of the attribute returned in the UserInfo Response that references the Name or Identifier of the end-user.
|
||||||
|
|
||||||
|
[[oauth2Client-client-registrations]]
|
||||||
|
==== ClientRegistrations
|
||||||
|
|
||||||
|
A `ClientRegistration` can be initially configured by hitting an authorization server's https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[Provider Configuration] endpoint or a https://tools.ietf.org/html/rfc8414#section-3[Authorization Server Metadata] endpoint.
|
||||||
|
|
||||||
|
`ClientRegistrations` provides convenience methods for generating a `ClientRegistration` in this way, as can be seen in the following example:
|
||||||
|
|
||||||
|
[source,java]
|
||||||
|
----
|
||||||
|
@Bean
|
||||||
|
public ClientRegistrationRepository clientRegistrationRepository() {
|
||||||
|
ClientRegistration clientRegistration =
|
||||||
|
ClientRegistrations.fromIssuerLocation("https://idp.example.com/issuer").build();
|
||||||
|
return new InMemoryClientRegistrationRepository(clientRegistration);
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
The above code will query in series `https://idp.example.com/issuer/.well-known/openid-configuration`, and then `https://idp.example.com/.well-known/openid-configuration/issuer`, and finally `https://idp.example.com/.well-known/oauth-authorization-server/issuer`, stopping at the first to return a 200 response.
|
||||||
|
|
||||||
|
As an alternative, you can invoke `ClientRegistrations#fromOidcIssuerLocation` to only hit the OIDC Provider Configuration endpoint.
|
||||||
|
|
||||||
[[oauth2Client-client-registration-repo]]
|
[[oauth2Client-client-registration-repo]]
|
||||||
==== ClientRegistrationRepository
|
==== ClientRegistrationRepository
|
||||||
|
|
|
@ -36,15 +36,15 @@ spring:
|
||||||
oauth2:
|
oauth2:
|
||||||
resourceserver:
|
resourceserver:
|
||||||
jwt:
|
jwt:
|
||||||
issuer-uri: https://idp.example.com
|
issuer-uri: https://idp.example.com/issuer
|
||||||
----
|
----
|
||||||
|
|
||||||
Where `https://idp.example.com` is the value contained in the `iss` claim for JWT tokens that the authorization server will issue.
|
Where `https://idp.example.com/issuer` is the value contained in the `iss` claim for JWT tokens that the authorization server will issue.
|
||||||
Resource Server will use this property to further self-configure, discover the authorization server's public keys, and subsequently validate incoming JWTs.
|
Resource Server will use this property to further self-configure, discover the authorization server's public keys, and subsequently validate incoming JWTs.
|
||||||
|
|
||||||
[NOTE]
|
[NOTE]
|
||||||
To use the `issuer-uri` property, it must also be true that `https://idp.example.com/.well-known/openid-configuration` is a supported endpoint for the authorization server.
|
To use the `issuer-uri` property, it must also be true that one of `https://idp.example.com/issuer/.well-known/openid-configuration`, `https://idp.example.com/.well-known/openid-configuration/issuer`, or `https://idp.example.com/.well-known/oauth-authorization-server/issuer` is a supported endpoint for the authorization server.
|
||||||
This endpoint is referred to as a https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[Provider Configuration] endpoint.
|
This endpoint is referred to as a https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[Provider Configuration] endpoint or a https://tools.ietf.org/html/rfc8414#section-3[Authorization Server Metadata] endpoint.
|
||||||
|
|
||||||
And that's it!
|
And that's it!
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ When this property and these dependencies are used, Resource Server will automat
|
||||||
|
|
||||||
It achieves this through a deterministic startup process:
|
It achieves this through a deterministic startup process:
|
||||||
|
|
||||||
1. Hit the Provider Configuration endpoint, `https://idp.example.com/.well-known/openid-configuration`, processing the response for the `jwks_url` property
|
1. Hit the Provider Configuration or Authorization Server Metadata endpoint, processing the response for the `jwks_url` property
|
||||||
2. Configure the validation strategy to query `jwks_url` for valid public keys
|
2. Configure the validation strategy to query `jwks_url` for valid public keys
|
||||||
3. Configure the validation strategy to validate each JWTs `iss` claim against `https://idp.example.com`.
|
3. Configure the validation strategy to validate each JWTs `iss` claim against `https://idp.example.com`.
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ From here, consider jumping to:
|
||||||
[[oauth2resourceserver-jwt-jwkseturi]]
|
[[oauth2resourceserver-jwt-jwkseturi]]
|
||||||
=== Specifying the Authorization Server JWK Set Uri Directly
|
=== Specifying the Authorization Server JWK Set Uri Directly
|
||||||
|
|
||||||
If the authorization server doesn't support the Provider Configuration endpoint, or if Resource Server must be able to start up independently from the authorization server, then `issuer-uri` can be exchanged for `jwk-set-uri`:
|
If the authorization server doesn't support any configuration endpoints, or if Resource Server must be able to start up independently from the authorization server, then the `jwk-set-uri` can be supplied as well:
|
||||||
|
|
||||||
[source,yaml]
|
[source,yaml]
|
||||||
----
|
----
|
||||||
|
@ -104,6 +104,7 @@ spring:
|
||||||
oauth2:
|
oauth2:
|
||||||
resourceserver:
|
resourceserver:
|
||||||
jwt:
|
jwt:
|
||||||
|
issuer-uri: https://idp.example.com
|
||||||
jwk-set-uri: https://idp.example.com/.well-known/jwks.json
|
jwk-set-uri: https://idp.example.com/.well-known/jwks.json
|
||||||
----
|
----
|
||||||
|
|
||||||
|
@ -111,7 +112,7 @@ spring:
|
||||||
The JWK Set uri is not standardized, but can typically be found in the authorization server's documentation
|
The JWK Set uri is not standardized, but can typically be found in the authorization server's documentation
|
||||||
|
|
||||||
Consequently, Resource Server will not ping the authorization server at startup.
|
Consequently, Resource Server will not ping the authorization server at startup.
|
||||||
However, it will also no longer validate the `iss` claim in the JWT (since Resource Server no longer knows what the issuer value should be).
|
We still specify the `issuer-uri` so that Resource Server still validates the `iss` claim on incoming JWTs.
|
||||||
|
|
||||||
[NOTE]
|
[NOTE]
|
||||||
This property can also be supplied directly on the <<oauth2resourceserver-jwt-jwkseturi-dsl,DSL>>.
|
This property can also be supplied directly on the <<oauth2resourceserver-jwt-jwkseturi-dsl,DSL>>.
|
||||||
|
@ -165,10 +166,13 @@ For example, the second `@Bean` Spring Boot creates is a `JwtDecoder`, which dec
|
||||||
----
|
----
|
||||||
@Bean
|
@Bean
|
||||||
public JwtDecoder jwtDecoder() {
|
public JwtDecoder jwtDecoder() {
|
||||||
return JwtDecoders.fromOidcIssuerLocation(issuerUri);
|
return JwtDecoders.fromIssuerLocation(issuerUri);
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
[NOTE]
|
||||||
|
Calling `{security-api-url}org/springframework/security/oauth2/jwt/JwtDecoders.html#fromIssuerLocation-java.lang.String-[JwtDecoders#fromIssuerLocation]` is what invokes the Provider Configuration or Authorization Server Metadata endpoint in order to derive the JWK Set Uri.
|
||||||
|
|
||||||
If the application doesn't expose a `JwtDecoder` bean, then Spring Boot will expose the above default one.
|
If the application doesn't expose a `JwtDecoder` bean, then Spring Boot will expose the above default one.
|
||||||
|
|
||||||
And its configuration can be overridden using `jwkSetUri()` or replaced using `decoder()`.
|
And its configuration can be overridden using `jwkSetUri()` or replaced using `decoder()`.
|
||||||
|
@ -512,7 +516,7 @@ Resource Server uses `JwtTimestampValidator` to verify a token's validity window
|
||||||
@Bean
|
@Bean
|
||||||
JwtDecoder jwtDecoder() {
|
JwtDecoder jwtDecoder() {
|
||||||
NimbusJwtDecoder jwtDecoder = (NimbusJwtDecoder)
|
NimbusJwtDecoder jwtDecoder = (NimbusJwtDecoder)
|
||||||
JwtDecoders.fromOidcIssuerLocation(issuerUri);
|
JwtDecoders.fromIssuerLocation(issuerUri);
|
||||||
|
|
||||||
OAuth2TokenValidator<Jwt> withClockSkew = new DelegatingOAuth2TokenValidator<>(
|
OAuth2TokenValidator<Jwt> withClockSkew = new DelegatingOAuth2TokenValidator<>(
|
||||||
new JwtTimestampValidator(Duration.ofSeconds(60)),
|
new JwtTimestampValidator(Duration.ofSeconds(60)),
|
||||||
|
@ -554,7 +558,7 @@ Then, to add into a resource server, it's a matter of specifying the `JwtDecoder
|
||||||
@Bean
|
@Bean
|
||||||
JwtDecoder jwtDecoder() {
|
JwtDecoder jwtDecoder() {
|
||||||
NimbusJwtDecoder jwtDecoder = (NimbusJwtDecoder)
|
NimbusJwtDecoder jwtDecoder = (NimbusJwtDecoder)
|
||||||
JwtDecoders.fromOidcIssuerLocation(issuerUri);
|
JwtDecoders.fromIssuerLocation(issuerUri);
|
||||||
|
|
||||||
OAuth2TokenValidator<Jwt> audienceValidator = new AudienceValidator();
|
OAuth2TokenValidator<Jwt> audienceValidator = new AudienceValidator();
|
||||||
OAuth2TokenValidator<Jwt> withIssuer = JwtValidators.createDefaultWithIssuer(issuerUri);
|
OAuth2TokenValidator<Jwt> withIssuer = JwtValidators.createDefaultWithIssuer(issuerUri);
|
||||||
|
|
Loading…
Reference in New Issue