es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Cómo especificar el alcance con la aplicación cliente de OAuth2.

Estoy utilizando la aplicación cliente de Spring Security OAuth2 y he proporcionado la siguiente configuración:

spring:
  security:
    oauth2:
      client:
        registration:
          okta:
            client-id: 
            client-secret: 
            scope: openid
        provider:
          okta:
            authorization-uri: https://dev-7858070.okta.com/oauth2/default/v1/authorize
            token-uri: https://dev-7858070.okta.com/oauth2/default/v1/token
            user-info-uri: https://dev-7858070.okta.com/oauth2/default/v1/userinfo
            jwk-set-uri: https://dev-7858070.okta.com/oauth2/default/v1/keys

He especificado el alcance ‘openid’ solamente, pero aún así obtengo otros alcances como ‘profile’ y ’email’. Solo quiero obtener el alcance ‘openid’. ¿Qué estoy haciendo mal?

Tags:  , ,

Answer

  1. Avatar for davy.ai

    La propiedad scope especifica el conjunto de alcances para los cuales tu aplicación solicita autorización. Sin embargo, no garantiza que solo esos alcances se devuelvan en el token de acceso. Depende de la implementación del servidor de autorización cómo determina los alcances que se concederán. En tu caso, parece que el servidor de autorización de Okta está concediendo alcances adicionales como profile y email, junto con openid.

    Para obtener solo el alcance openid, puedes configurar tu servidor de autorización de Okta para que solo devuelva ese alcance. Esto se puede hacer yendo a la Consola de Desarrollador de Okta, seleccionando tu servidor de autorización, haciendo clic en la pestaña “Alcances” y eliminando los alcances adicionales.

    Alternativamente, puedes modificar tu aplicación para usar solo el alcance openid y omitir los otros alcances. Esto se puede hacer añadiendo un convertidor de respuesta de token personalizado (TokenResponseConverter) que filtre los alcances que no te interesan. Aquí tienes un ejemplo de cómo puedes lograr esto:

    @Configuration
    public class OAuth2Config {
    
        @Bean
        public ClientRegistrationRepository clientRegistrationRepository() {
            return new InMemoryClientRegistrationRepository(oktaClientRegistration());
        }
    
        @Bean
        public OAuth2AuthorizedClientService authorizedClientService() {
            return new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository());
        }
    
        @Bean
        public OAuth2AccessTokenResponseClient<oauth2clientcredentialsgrantrequest> accessTokenResponseClient() {
            return new WebClientReactiveOAuth2AccessTokenResponseClient();
        }
    
        @Bean
        public ClientRegistration oktaClientRegistration() {
            return ClientRegistration.withRegistrationId("okta")
                    .clientId("okta-client-id")
                    .clientSecret("okta-client-secret")
                    .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
                    .scope("openid") // Solo solicita el alcance openid
                    .authorizationUri("https://dev-7858070.okta.com/oauth2/default/v1/authorize")
                    .tokenUri("https://dev-7858070.okta.com/oauth2/default/v1/token")
                    .userInfoUri("https://dev-7858070.okta.com/oauth2/default/v1/userinfo")
                    .jwkSetUri("https://dev-7858070.okta.com/oauth2/default/v1/keys")
                    .clientName("Okta")
                    .build();
        }
    
        @Bean
        public WebClient webClient() {
            return WebClient.builder().build();
        }
    
        @Bean
        public OAuth2AccessTokenResponseConverter<oauth2accesstokenresponse> accessTokenResponseConverter() {
            return new OAuth2AccessTokenResponseConverter<oauth2accesstokenresponse>() {
                @Override
                public OAuth2AccessTokenResponse convert(OAuth2AccessTokenResponse tokenResponse) {
                    Set<string> filteredScopes = new HashSet<>(Arrays.asList("openid"));
                    OAuth2AccessToken.TokenType tokenType = tokenResponse.getAccessToken().getTokenType();
                    long expiresIn = tokenResponse.getAccessToken().getExpiresAt().toEpochMilli() - System.currentTimeMillis();
    
                    return OAuth2AccessTokenResponse.withToken(tokenResponse.getAccessToken().getValue())
                            .tokenType(tokenType)
                            .expiresIn(expiresIn)
                            .refreshToken(tokenResponse.getRefreshToken().getValue())
                            .scopes(filterScopes(tokenResponse.getAccessToken().getScopes(), filteredScopes))
                            .build();
                }
    
                private Set<string> filterScopes(Set<string> scopes, Set<string> filteredScopes) {
                    return scopes.stream()
                            .filter(filteredScopes::contains)
                            .collect(Collectors.toSet());
                }
            };
        }
    
        @Bean
        public WebClientReactiveOAuth2AuthorizedClientManager authorizedClientManager(
                ClientRegistrationRepository clientRegistrationRepository,
                OAuth2AuthorizedClientRepository authorizedClientRepository) {
    
            WebClientReactiveOAuth2AuthorizedClientManager authorizedClientManager =
                    new WebClientReactiveOAuth2AuthorizedClientManager(
                            clientRegistrationRepository, authorizedClientRepository);
            authorizedClientManager.setAuthorizedClientProvider(new DefaultReactiveOAuth2AuthorizedClientProvider(
                    OAuth2ClientCredentialsGrantRequest.class, new WebClientReactiveOAuth2AccessTokenResponseClient()));
            authorizedClientManager.setContextAttributesMapper(this::getContextAttributes);
            authorizedClientManager.setAccessTokenResponseClient(accessTokenResponseClient());
            authorizedClientManager.setAuthorizationSuccessHandler(new WebSessionOAuth2AuthorizationSuccessHandler());
    
            return authorizedClientManager;
        }
    
        private Mono<oauth2authorizedclient> getContextAttributes(Mono<oauth2authorizedclient> authorizedClientMono, Authentication authentication) {
            return authorizedClientMono;
        }
    }
    

    En este ejemplo, hemos sobrescrito el bean accessTokenResponseConverter para filtrar cualquier alcance que no esté en el conjunto filteredScopes (que en este caso solo contiene openid). También se modifica el bean authorizedClientManager para usar este nuevo convertidor, de modo que el token de acceso devuelto por el servidor se analice con la lógica personalizada.

Comments are closed.