Serwery, OAuth Client, SecurityFilterChain

i ciut więcej ze Spring Security

Perspektywa... ma znaczenie :)

Auth

Authentication Authorization

Auth

github.com/nurkiewicz/polski-w-it
Uwierzytelnianie Autoryzacja
📚 Explore the full series:
1️⃣ Introduction 📝

Deep diving in Spring Security with the latest trends and additions By Laur Spilca

OAuth 2.1

+--------+                               +---------------+
|        |--(1)- Authorization Request ->|   Resource            |
|        |                               |     Owner   użytkownik  |
|        |<-(2)-- Authorization Grant ---|               |
|        |                               +---------------+
|        |
|        |                               +---------------+
|        |--(3)-- Authorization Grant -->| Authorization              |
| Client frontend|                               |     Server Okta     |
|        |<-(4)----- Access Token -------|               |
|        |                               +---------------+
|        |
|        |                               +---------------+
|        |--(5)----- Access Token ------>|    Resource           |
|        |                               |     Serverbackend    |
|        |<-(6)--- Protected Resource ---|               |
+--------+                               +---------------+
                

Spring Security Arch

Spring Security Arch

Spring Security Arch

Spring Security Arch

Spring Security Arch

Spring Security Arch


                @Bean
                @Order(0)
                SecurityFilterChain oidcProtocolEndpointsChain(
                  HttpSecurity http,
                  UserDetailsService userDetailsService,
                  PasswordEncoder passwordEncoder,
                  OAuth2AuthorizationService authorizationService,
                  OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator
                ) throws Exception {
                  OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
                  http
                    .getConfigurer(OAuth2AuthorizationServerConfigurer.class)
                    .oidc(withDefaults())
                    .tokenEndpoint(tokenEndpoint -> tokenEndpoint
                      .accessTokenRequestConverter(new OAuth2PasswordGrantAuthenticationConverter())
                      .authenticationProvider(new OAuth2PasswordGrantAuthenticationProvider(userDetailsService, passwordEncoder, authorizationService, tokenGenerator)));
                  return http.exceptionHandling(exceptions -> exceptions.authenticationEntryPoint(
                     new LoginUrlAuthenticationEntryPoint("/oauth2/authorization/okta"))
                  ).build();
                }
                

Resource Server

Configurer, Customizer


                    @Bean
                    @Order(2)
                    SecurityFilterChain oauthChain(
                        HttpSecurity http,
                        Customizer<AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry> permissionsCustomizer
                    ) throws Exception {
                      return http
                          .oauth2ResourceServer(oauth2 -> oauth2.jwt(withDefaults()))
                          .csrf(AbstractHttpConfigurer::disable)
                          .cors(AbstractHttpConfigurer::disable)
                          .sessionManagement(session ->
                            session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                          .authorizeHttpRequests(permissionsCustomizer)
                          .build();
                    }
                

OAuth 2.1

+--------+                               +---------------+
|        |--(1)- Authorization Request ->|               |
|        |                               |   użytkownik  |
|        |<-(2)-- Authorization Grant ---|               |
|        |                               +---------------+
|        |
|        |                               +---------------+
|        |--(3)-- Authorization Grant -->|               |
|frontend|                               |      Okta     |
|        |<-(4)----- Access Token -------|               |
|        |                               +---------------+
|        |
|        |                               +---------------+
|        |--(5)----- Access Token ------>|               |
|        |                               |    backend    |
|        |<-(6)--- Protected Resource ---|               |
+--------+                               +---------------+
                

                    <dependency>
                        <groupId>com.okta.spring</groupId>
                        <artifactId>okta-spring-boot-starter</artifactId>
                    </dependency>
                
Okta Developer Edition (forever-free) ⇒ Integrator Free Plan

                    <dependency>
                        <groupId>com.okta.spring</groupId>
                        <artifactId>okta-spring-boot-starter</artifactId>
                        <version>${okta.springboot.version}</version>
                    </dependency>
                
Okta Developer Edition (forever-free) ⇒ Integrator Free Plan

                    org.springframework.security.oauth2.server.resource.InvalidBearerTokenException:
                        An error occurred while attempting to decode the Jwt: JOSE header typ (type) application/okta-internal-at+jwt not allowed
                
Forum

Org authorization server

Every Okta org comes equipped with a built-in org authorization server. The org authorization server issues access tokens for accessing Okta resources in your Okta org domain. Use the org authorization server to perform Single Sign-On (SSO) with Okta for your OIDC apps or to get an access token to access Okta APIs.
Note: In the org authorization server, Okta is the resource server.

(...)

Custom authorization server

(...)

Default custom authorization server

(...)
Okta docs

                    https://{yourOktaDomain}.okta.com/.well-known/openid-configuration
                

                    https://{yourOktaDomain}.okta.com/oauth2/default/.well-known/openid-configuration
                

OAuth 2.1

+--------+                               +---------------+
|        |--(1)- Authorization Request ->|               |
|        |                               |   użytkownik  |
|        |<-(2)-- Authorization Grant ---|               |
|        |                               +---------------+
|        |
|        |                               +---------------+
|        |--(3)-- Authorization Grant -->|               |
|frontend|                               |      Okta     |
|        |<-(4)----- Access Token -------|               |
|        |                               +---------------+
|        |
|        |                               +---------------+
|        |--(5)----- Access Token ------>|               |
|        |                               |    backend    |
|        |<-(6)--- Protected Resource ---|               |
+--------+                               +---------------+
                

Grupy AD?

  • Mało elastyczne w dużej organizacji
  • Większy self-service dla kierowników zespołów

JWT scope?

  • Klient deklaruje o jakie scope pyta (opcjonalnie)
    • Brak? Domyślny (mały) zakres (PoLP)
    • Klient, nie użytkownik
  • scope = co wolno z tym tokenem (gruboziarniste)

PoC uprawnień - 1/2

  • 100-200 już istniejących endpointów
  • Powtarzalne, ~konwencja
    • GET /collection/{id}
    • POST /asset
    • PATCH /promotion/{id}/publication
  • Domyślnie zabezpieczyć
  • Łatwość definiowania nowych uprawnień

PoC uprawnień - 2/2


                    admin.permissions:
                      resources: asset, promotion, collection
                      operations: view, modify, publish
                      metapermissions: role.delete, role.modify, role.view
                

                    @ConfigurationProperties("admin.permissions")
                    class Permissions {
                      void authorize(HttpSecurity http) {
                        resources.forEach(resource -> operations.forEach(operation ->
                            () -> http.authorizeHttpRequests(operation.on(resource))));
                      }

                      enum Operations {
                        view(GET), modify(POST, PATCH, PUT), publish("/publication/**", PATCH);

                        Customizer<AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry> on(String resource) {
                          return authorize -> matchingMethods.forEach(httpMethod ->
                            authorize.requestMatchers(httpMethod, resource + "/**" + additionalPath)
                              .access(hasAuthority(resource + "." + name())));
                        }

                        private final Set<HttpMethod> matchingMethods;
                        private final String additionalPath;
                      }
                    }
                

application-security.yaml (protip)

  • Wszystko związane z zabezpieczeniami od razu tam
  • Profil=środowisko? Niekoniecznie (~zmienne środowiskowe)
    • Profile grupujące podobne właściwości
    • Uruchamianie wielu jednocześnie
  • Łatwo lokalnie (kompatybilność wsteczna)

                    @Configuration(proxyBeanMethods = false)
                    class SecurityConfiguration {
                      @Profile({"!security"})
                      @Bean
                      SecurityFilterChain noAuthenticationFilterChain(HttpSecurity http) throws Exception {
                        return http
                          .csrf(AbstractHttpConfigurer::disable)
                          .cors(AbstractHttpConfigurer::disable);
                          .authorizeHttpRequests((request) ->
                              request.anyRequest().permitAll());
                          .build();
                      }

                      @Profile({"security"})
                      @Configuration(proxyBeanMethods = false)
                      @EnableConfigurationProperties(BasicAuthSettings.class)
                      static class SecurityTurnedOn {
                        // all other filter chains here
                      }
                    }
                

OAuth 2.1

+--------+                               +---------------+
|        |--(1)- Authorization Request ->|               |
|        |                               |   użytkownik  |
|        |<-(2)-- Authorization Grant ---|               |
|        |                               +---------------+
|        |
|        |                               +---------------+
|        |--(3)-- Authorization Grant -->|               |
|frontend|                               |      Okta backend           |
|        |<-(4)----- Access Token -------|               |
|        |                               +---------------++               +
|        |                               |    backend    |
|        |                               +---------------++               +
|        |--(5)----- Access Token ------>|               |
|        |                               |    backend           |
|        |<-(6)--- Protected Resource ---|               |
+--------+                               +---------------+
                

Spring Security Arch

Spring Security Arch

Spring Security Arch


                    // DisabledException, LockedException, BadCredentialsException
                    public interface AuthenticationManager {
                        Authentication authenticate(Authentication authentication)
                            throws AuthenticationException;
                    }
                

Spring Security Arch


                @Bean
                @Order(0)
                SecurityFilterChain oidcProtocolEndpointsChain(
                  HttpSecurity http,
                  UserDetailsService userDetailsService,
                  PasswordEncoder passwordEncoder,
                  OAuth2AuthorizationService authorizationService,
                  OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator
                ) throws Exception {
                  OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
                  http
                    .getConfigurer(OAuth2AuthorizationServerConfigurer.class)
                    .oidc(withDefaults())
                    .tokenEndpoint(tokenEndpoint -> tokenEndpoint
                      .accessTokenRequestConverter(new OAuth2PasswordGrantAuthenticationConverter())
                      .authenticationProvider(new OAuth2PasswordGrantAuthenticationProvider(userDetailsService, passwordEncoder, authorizationService, tokenGenerator)));
                  return http.exceptionHandling(exceptions -> exceptions.authenticationEntryPoint(
                     new LoginUrlAuthenticationEntryPoint("/oauth2/authorization/okta"))
                  ).build();
                }
                

Spring Security Arch


                    /**
                     * ...
                     * @throws UsernameNotFoundException if the user
                     * could not be found or the user has no
                     * GrantedAuthority
                     */
                    public interface UserDetailsService {
                        UserDetails loadUserByUsername(String username)
                            throws UsernameNotFoundException;
                    }
                

Spring Security Arch

OAuth 2.1

+--------+                               +---------------+
|        |--(1)- Authorization Request ->|               |
|        |                               |   użytkownik  |
|        |<-(2)-- Authorization Grant ---|               |
|        |                               +---------------+
|        |
|        |                               +---------------+
|        |--(3)-- Authorization Grant -->|               |
|frontend|                               |               |
|        |<-(4)----- Access Token -------|               |
|        |                               +               +
|        |                               |    backend    |
|        |                               +               +
|        |--(5)----- Access Token ------>|               |
|        |                               |               |
|        |<-(6)--- Protected Resource ---|               |
+--------+                               +---------------+
                

Authorization Code Flow

+----------+
| Resource |
|   Owner  |
+----------+
      ^
      |
      |
+------|----+          Client Identifier      +---------------+
| .---+---------(1)-- & Redirect URI ------->|               |
| |   |    |                                 |               |
| |   '----|-----(2)-- User authenticates --->|               |
| | User-  |                                 | Authorization |
| | Agent  |                                 |     Server    |
| |        |                                 |               |
| |    .---|-----(3)-- Authorization Code ---<|               |
+-|-----|---+                                 +---------------+
  |    |                                         ^      v
  |    |                                         |      |
  ^    v                                         |      |
+---------+                                      |      |
|         |>---(4)-- Authorization Code ---------'      |
|  Client |          & Redirect URI                     |
|         |                                             |
|         |<---(5)----- Access Token -------------------'
+---------+       (w/ Optional Refresh Token)
                
  • [przekierowanie] PKCE (code challenge)
  • [przekierowanie] Jednorazowy kod
  • PKCE (code verifier)
Spring Security Authorization Server (kod)

                @Bean
                @Order(0)
                SecurityFilterChain oidcProtocolEndpointsChain(
                  HttpSecurity http,
                  UserDetailsService userDetailsService,
                  PasswordEncoder passwordEncoder,
                  OAuth2AuthorizationService authorizationService,
                  OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator
                ) throws Exception {
                  OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
                  http
                    .getConfigurer(OAuth2AuthorizationServerConfigurer.class)
                    .oidc(withDefaults())
                    .tokenEndpoint(tokenEndpoint -> tokenEndpoint
                      .accessTokenRequestConverter(new OAuth2PasswordGrantAuthenticationConverter())
                      .authenticationProvider(new OAuth2PasswordGrantAuthenticationProvider(userDetailsService, passwordEncoder, authorizationService, tokenGenerator)));
                  return http.exceptionHandling(exceptions -> exceptions.authenticationEntryPoint(
                     new LoginUrlAuthenticationEntryPoint("/oauth2/authorization/okta"))
                  ).build();
                }

                @Bean
                @Order(1)
                SecurityFilterChain oktaLoginChain(HttpSecurity http, UserService userService) throws Exception {
                  return http
                      .securityMatcher(anyOf(antMatcher("/oauth2/**"), antMatcher("/login/oauth2/**")))
                      .authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated())
                      .oauth2Login(oauth2Login -> oauth2Login.successHandler(new CreateUserHandler(userService, requestCache)))
                      .build();
                }
                
Spring Security Authorization Server (YAML)

                    spring.security:
                      oauth2:
                        authorizationserver:
                          client:
                            frontend:
                              registration:
                                client-id: ${app.security.frontend.client-id}
                                client-secret: "{noop}${app.security.frontend.client-secret}"
                                client-authentication-methods:
                                  - client_secret_post
                                authorization-grant-types:
                                  - authorization_code
                                  - refresh_token
                                  - password
                                redirect-uris:
                                  - ${app.frontend.url}/api/auth/callback/backend
                                post-logout-redirect-uris:
                                  - ${app.frontend.url}/api/auth/callback/backend
                                scopes:
                                  - openid
                                  - profile
                                  - email
                                  - offline_access
                              token:
                                access-token-time-to-live: P6D
                                refresh-token-time-to-live: P6D
                              require-proof-key: true
                

                    spring.security:
                      oauth2:
                        authorizationserver:
                          # how external apps connect this
                          client:
                            frontend:
                              registration:
                                client-id: ${app.security.frontend.client-id}
                                client-secret: "{noop}${app.security.frontend.client-secret}"
                                client-authentication-methods:
                                  - client_secret_post
                                authorization-grant-types:
                                  - authorization_code
                                  - refresh_token
                                  - password
                                redirect-uris:
                                  - ${app.frontend.url}/api/auth/callback/backend
                                post-logout-redirect-uris:
                                  - ${app.frontend.url}/api/auth/callback/backend
                                scopes:
                                  - openid
                                  - profile
                                  - email
                                  - offline_access
                              token:
                                access-token-time-to-live: P6D
                                refresh-token-time-to-live: P6D
                              require-proof-key: true
                
 +----------+
 | Resource |
 |   Owner  |
 +----------+
       ^
       |
       |
 +-----|----+          Client Identifier      +---------------+
 | .---+---------(1)-- & Redirect URI ------->|               |
 | |   |    |                                 |               |
 | |   '---------(2)-- User authenticates --->|               |
 | | User-  |                                 | Authorization |
 | | Agent  |                                 |     Server    |
 | |        |                                 |               |
 | |    .--------(3)-- Authorization Code ---<|               |
 +-|----|---+                                 +---------------+
   |    |                                         ^      v
   |    |                                         |      |
   ^    v                                         |      |
 +---------+                                      |      |
 |         |>---(4)-- Authorization Code ---------'      |
 |  Client |          & Redirect URI                     |
 |         |                                             |
 |         |<---(5)----- Access Token -------------------'
 +---------+       (w/ Optional Refresh Token)
                    
 +----------+
 | Resource |
 |   Owner  |
 +----------+
       ^
       |
       |
 +-----|----+          Client Identifier      +---------------+
 | .---+---------(1)-- & Redirect URI ------->|               |
 | |   |    |                                 |               |
 | |   '---------(2)-- User authenticates --->|               |
 | | User-  |                                 | Authorization |
 | | Agent  |                                 |     Server    |
 | |        |                                 |               |
 | |    .--------(3)-- Authorization Code ---<|               |
 +-|----|---+                                 +---------------+
   |    |                                         ^      v
   |    |                                         |      |
   ^    v                                         |      |
 +---------+                                      |      |
 |         |>---(4)-- Authorization Code ---------'      |
 |  Client |          & Redirect URI                     |
 |         |                                             |
 |         |<---(5)----- Access Token -------------------'
 +---------+       (w/ Optional Refresh Token)
                    
 +----------+                                                        +---------------+
 | Resource |                                                        |               |
 |   Owner  |                                                        |               |
 +----------+                                  .-(2.5)- OAuth flow ->|      Okta     |
       ^                                       |                     | Authorization |
       |                                       |                     |     Server    |
       |                                       ^                     |               |
 +-----|----+          Client Identifier      +---------------+      |               |
 | .---+---------(1)-- & Redirect URI ------->|               |      +---------------+
 | |   |    |                                 |               |                    v
 | |   '---------(2)-- User authenticates --->|               |                    |
 | | User-  |                                 | Authorization |                    |
 | | Agent  |                                 |     Server    |<-(2¾)- OAuth flow -'
 | |        |                                 |               |
 | |    .--------(3)-- Authorization Code ---<|               |
 +-|----|---+                                 +---------------+
   |    |                                         ^      v
   |    |                                         |      |
   ^    v                                         |      |
 +---------+                                      |      |
 |         |>---(4)-- Authorization Code ---------'      |
 |  Client |          & Redirect URI                     |
 |         |                                             |
 |         |<---(5)----- Access Token -------------------'
 +---------+       (w/ Optional Refresh Token)
                    
OAuth Client

                    spring.security:
                      oauth2:
                        authorizationserver:
                          # how external apps connect this
                          client:
                            frontend:
                              registration:
                                client-id: ${app.security.frontend.client-id}
                                client-secret: "{noop}${app.security.frontend.client-secret}"
                                client-authentication-methods:
                                  - client_secret_post
                                authorization-grant-types:
                                  - authorization_code
                                  - refresh_token
                                  - password
                                redirect-uris:
                                  - ${app.frontend.url}/api/auth/callback/backend
                                post-logout-redirect-uris:
                                  - ${app.frontend.url}/api/auth/callback/backend
                                scopes:
                                  - openid
                                  - profile
                                  - email
                                  - offline_access
                              token:
                                access-token-time-to-live: P6D
                                refresh-token-time-to-live: P6D
                              require-proof-key: true
                
OAuth Client

                    spring.security:
                      oauth2:
                        # how this connects Okta
                        client:
                          registration:
                            okta:
                              provider: okta
                              client-id: ${app.security.okta.client-id}
                              client-secret: ${app.security.okta.client-secret}
                              scope:
                                - openid
                                - profile
                                - email
                                - offline_access
                          provider:
                            okta:
                              authorization-uri: ${okta.oauth2.issuer}/v1/authorize
                              token-uri: ${okta.oauth2.issuer}/v1/token
                              user-info-uri: ${okta.oauth2.issuer}/v1/userinfo
                              jwk-set-uri: ${okta.oauth2.issuer}/v1/keys
                              user-name-attribute: sub
                        authorizationserver:
                          # how external apps connect this
                          client:
                            frontend:
                              registration:
                                client-id: ${app.security.frontend.client-id}
                                client-secret: "{noop}${app.security.frontend.client-secret}"
                                client-authentication-methods:
                                  - client_secret_post
                                authorization-grant-types:
                                  - authorization_code
                                  - refresh_token
                                  - password
                                redirect-uris:
                                  - ${app.frontend.url}/api/auth/callback/backend
                                post-logout-redirect-uris:
                                  - ${app.frontend.url}/api/auth/callback/backend
                                scopes:
                                  - openid
                                  - profile
                                  - email
                                  - offline_access
                              token:
                                access-token-time-to-live: P6D
                                refresh-token-time-to-live: P6D
                              require-proof-key: true
                
Resource + Authorization w jednym
  • Nieczęste (przykład, drugi)
  • Może klucz symetryczny?
  • Łatwo testować - JwtDecoder i JwtEncoder
  • Uwaga na wspólny kontekst Springa, np. sesje

Swagger (springdoc-openapi)


                    @SecurityScheme(
                        name = "openid-connect",
                        type = SecuritySchemeType.OPENIDCONNECT,
                        openIdConnectUrl = "/api/.well-known/openid-configuration")
                    @SecurityScheme(
                        name = "bearer-jwt",
                        type = SecuritySchemeType.HTTP,
                        description = "Fallback method - paste any access token you obtained",
                        scheme = "bearer",
                        bearerFormat = "JWT")
                    @OpenAPIDefinition(
                        info = @Info(
                            title = "${app.title}",
                            description = "${app.description}",
                            version = "${app.version}"),
                        security = {
                            @SecurityRequirement(name = "openid-connect", scopes = "openid"),
                            @SecurityRequirement(name = "bearer-jwt")})
                    @Configuration(proxyBeanMethods = false)
                    class SecurityOpenAPI {}
                

                    spring.security:
                      oauth2:
                        # how this connects Okta
                        client:
                          registration:
                            okta:
                              provider: okta
                              client-id: ${app.security.okta.client-id}
                              client-secret: ${app.security.okta.client-secret}
                              scope:
                                - openid
                                - profile
                                - email
                                - offline_access
                          provider:
                            okta:
                              authorization-uri: ${okta.oauth2.issuer}/v1/authorize
                              token-uri: ${okta.oauth2.issuer}/v1/token
                              user-info-uri: ${okta.oauth2.issuer}/v1/userinfo
                              jwk-set-uri: ${okta.oauth2.issuer}/v1/keys
                              user-name-attribute: sub
                        authorizationserver:
                          # how external apps connect this
                          client:
                            reco:
                              registration:
                                client-id: ${app.security.reco.client-id}
                                client-secret: "{noop}${app.security.reco.client-secret}"
                                client-authentication-methods:
                                  - client_secret_basic
                                authorization-grant-types:
                                  - client_credentials
                                scopes:
                                  - openid
                                  - offline_access
                            frontend:
                              registration:
                                client-id: ${app.security.frontend.client-id}
                                client-secret: "{noop}${app.security.frontend.client-secret}"
                                client-authentication-methods:
                                  - client_secret_post
                                authorization-grant-types:
                                  - authorization_code
                                  - refresh_token
                                  - password
                                redirect-uris:
                                  - ${app.frontend.url}/api/auth/callback/backend
                                post-logout-redirect-uris:
                                  - ${app.frontend.url}/api/auth/callback/backend
                                scopes:
                                  - openid
                                  - profile
                                  - email
                                  - offline_access
                              token:
                                access-token-time-to-live: P6D
                                refresh-token-time-to-live: P6D
                              require-proof-key: true
                

                    spring.security:
                      oauth2:
                        # how this connects Okta
                        client:
                          registration:
                            okta:
                              provider: okta
                              client-id: ${app.security.okta.client-id}
                              client-secret: ${app.security.okta.client-secret}
                              scope:
                                - openid
                                - profile
                                - email
                                - offline_access
                          provider:
                            okta:
                              authorization-uri: ${okta.oauth2.issuer}/v1/authorize
                              token-uri: ${okta.oauth2.issuer}/v1/token
                              user-info-uri: ${okta.oauth2.issuer}/v1/userinfo
                              jwk-set-uri: ${okta.oauth2.issuer}/v1/keys
                              user-name-attribute: sub
                        authorizationserver:
                          # how external apps connect this
                          client:
                            reco:
                              registration:
                                client-id: ${app.security.reco.client-id}
                                client-secret: "{noop}${app.security.reco.client-secret}"
                                client-authentication-methods:
                                  - client_secret_basic
                                authorization-grant-types:
                                  - client_credentials
                                scopes:
                                  - openid
                                  - offline_access
                            frontend:
                              registration:
                                client-id: ${app.security.frontend.client-id}
                                client-secret: "{noop}${app.security.frontend.client-secret}"
                                client-authentication-methods:
                                  - client_secret_basic
                                  - client_secret_post
                                authorization-grant-types:
                                  - authorization_code
                                  - refresh_token
                                  - password
                                redirect-uris:
                                  - ${app.frontend.url}/api/auth/callback/backend
                                  - http://localhost:8080/api/swagger-ui/oauth2-redirect.html
                                post-logout-redirect-uris:
                                  - ${app.frontend.url}/api/auth/callback/backend
                                scopes:
                                  - openid
                                  - profile
                                  - email
                                  - offline_access
                              token:
                                access-token-time-to-live: P6D
                                refresh-token-time-to-live: P6D
                              require-proof-key: true
                

Dziękuję!