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.

Autenticación openid y tokens de actualización de Micronaut.

Estoy implementando una pasarela API usando micronaut. Una de las responsabilidades de la pasarela es manejar la autenticación de usuario. Quiero utilizar un proveedor de identidad externo para autenticar a los usuarios y luego propagar el token JWT a los servicios aguas abajo.

No quiero que micronaut genere su propio token, sino que quiero que se utilice el token generado por el proveedor de identidad.

La configuración de seguridad de mi servicio de pasarela es similar a la descrita aquí: https://guides.micronaut.io/latest/micronaut-oauth2-okta-gradle-java.html

En resumen:

security:
  authentication: idtoken 
  oauth2:
    clients:
      provider: 
        client-secret: '${OAUTH_CLIENT_SECRET:yyy}' 
        client-id: '${OAUTH_CLIENT_ID:xxx}' 
        openid:
          issuer: '${OIDC_ISSUER_DOMAIN}/oauth2' 
  endpoints:
    logout:
      get-allowed: true

Después de una autenticación exitosa, obtengo el token JWT como cookie y puedo usarlo para autorizar mis solicitudes. Todo funciona muy bien hasta el momento.

Los tokens emitidos por el proveedor de identidad tienen un período de validez corto y ese es el comportamiento esperado. Quiero que la vida útil del JWT sea corta y obtener otros nuevos usando tokens de actualización.

Estoy buscando una manera de implementar el flujo de actualización de token en micronaut.

La solución perfecta sería la siguiente:

  • Se devuelven tanto el token JWT como el token de actualización después de una autenticación exitosa como cookies,
  • Si la pasarela recibe una solicitud con un JWT expirado, automáticamente se obtiene uno nuevo usando el token de actualización,
  • El nuevo JWT (y un nuevo token de actualización si se emite) se establecen como cookies.

La primera pregunta es cómo configurar micronaut para devolver el token de actualización al llamador (como devuelve los JWT). Es posible devolver el token de actualización generado por micronaut (por ejemplo, en una cookie), pero no encontré una manera de obtener el token de actualización generado por el proveedor de identidad externo.

La segunda pregunta es si es posible configurar micronaut para ejecutar automáticamente todo el flujo del token de actualización (parece ser un problema bastante estándar). ¿O tal vez hay otra biblioteca que se puede usar para lograr ese objetivo?

Agradeceré cualquier sugerencia.

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Uso de IdP externo para propagar token JWT en la puerta de enlace de la API Micronaut

    Como experto en TI especializado en [JWT] (https://jwt.io/), [Micronaut] (https://micronaut.io/), [refresh-token] (https://auth0.com/learn/refresh-tokens/) y [Micronaut-security] (https://micronaut.io/solutions/security/), se le pide que implemente una puerta de enlace de API utilizando Micronaut que maneje la autenticación de usuarios usando un IdP externo.

    Sin embargo, no desea que Micronaut genere su propio token, sino que use el token generado por IdP en su lugar. La configuración de seguridad de su servicio de puerta de enlace es similar a la descrita en esta [guía Micronaut OAuth2 Okta] (https://guides.micronaut.io/latest/micronaut-oauth2-okta-gradle-java.html).

    Después de una autenticación exitosa, obtiene un JWT como una cookie y puede usarlo para autorizar sus solicitudes. Sin embargo, los tokens emitidos por IdP tienen un período de validez corto y desea que la vida útil de JWT sea corta y obtener nuevos utilizando tokens de actualización. Desea implementar un flujo de tokens de actualización en Micronaut y busca una manera de lograrlo.

    Solución

    Hay dos preguntas que debe abordar:

    1. ¿Cómo configurar Micronaut para devolver el token de actualización al llamante?
    2. ¿Cómo configurar Micronaut para ejecutar automáticamente el flujo completo de tokens de actualización?

    Devolviendo el token de actualización al llamante

    Micronaut puede devolver el token de actualización generado por Micronaut como una cookie, pero si desea obtener el token de actualización generado por un IdP externo, necesita obtenerlo de las cabeceras de respuesta.

    Puede lograr esto interceptando la respuesta de autenticación y extrayendo el token de actualización de las cabeceras de respuesta. Una forma de hacer esto es creando un AuthenticationSuccessHandler personalizado que intercepta la respuesta de autenticación y extrae el token de actualización de las cabeceras de respuesta.

    import io.micronaut.security.authentication.Authentication;
    import io.micronaut.security.authentication.AuthenticationResponse;
    import io.micronaut.security.handlers.AuthenticationSuccessHandler;
    
    import javax.inject.Singleton;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    @Singleton
    public class RefreshTokenAuthSuccessHandler implements AuthenticationSuccessHandler {
    
        @Override
        public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
            AuthenticationResponse authenticationResponse = (AuthenticationResponse) authentication;
            String refreshToken = authenticationResponse.getHeaders().get("refresh_token");
            // Devuelve el token de actualización como una cookie
            response.addCookie(new Cookie("refresh_token", refreshToken));
        }
    }
    

    Ahora, puede registrar su AuthenticationSuccessHandler personalizado en la configuración de seguridad de Micronaut.

    security:
      authentication: idtoken 
      oauth2:
        clients:
          proveedor: 
            client-secret: '${OAUTH_CLIENT_SECRET:yyy}' 
            client-id: '${OAUTH_CLIENT_ID:xxx}' 
            openid:
              issuer: '${OIDC_ISSUER_DOMAIN}/oauth2' 
      endpoints:
        logout:
          get-allowed: true
      handlers:
        authenticated:
          successHandler: refresh-token-auth-success-handler
    
    beans:
      refresh-token-auth-success-handler:
        class: com.example.security.RefreshTokenAuthSuccessHandler
    

    Ejecución automática del flujo completo de actualización de tokens

    Para ejecutar automáticamente el flujo completo de tokens de actualización en Micronaut, puede usar la biblioteca [auth0 / java-jwt] (https://github.com/auth0/java-jwt).

    Primero, debe validar el JWT utilizando la clave pública del IdP.

    import com.auth0.jwt.JWT;
    import com.auth0.jwt.JWTVerifier;
    import com.auth0.jwt.algorithms.Algorithm;
    
    import java.security.interfaces.RSAPublicKey;
    
    public class JwtUtil {
        public static void verifyAndDecode(String token, RSAPublicKey publicKey) {
            Algorithm algorithm = Algorithm.RSA256(publicKey, null);
            JWTVerifier verifier = JWT.require(algorithm).build();
            verifier.verify(token);
            // Decodifica el token para obtener las reclamaciones
            // ...
        }
    }
    

    Luego, debe verificar si el token ha caducado y, de ser así, usar el token de actualización para obtener un nuevo JWT.

    import com.auth0.jwt.exceptions.TokenExpiredException;
    
    public class JwtUtil {
        public static void verifyAndDecode(String token, String refreshToken, RSAPublicKey publicKey) {
            Algorithm algorithm = Algorithm.RSA256(publicKey, null);
            JWTVerifier verifier = JWT.require(algorithm).build();
            try {
                verifier.verify(token);
                // Decodifica el token para obtener las reclamaciones
            } catch (TokenExpiredException e) {
                // Usa el token de actualización para obtener un nuevo JWT
                // ...
            }
        }
    }
    

    Luego, puede usar su clase JwtUtil personalizada para verificar y decodificar el JWT en sus métodos de controlador.

    import io.micronaut.http.annotation.Controller;
    import io.micronaut.http.annotation.Get;
    
    import java.security.interfaces.RSAPublicKey;
    
    @Controller
    public class MyController {
        private final RSAPublicKey publicKey; // Clave pública inyectada del IdP
    
        public MyController(RSAPublicKey publicKey) {
            this.publicKey = publicKey;
        }
    
        @Get("/my-resource")
        public void myResource(String token) {
            JwtUtil.verifyAndDecode(token, publicKey);
            // ...
        }
    }
    

    En conclusión, para implementar un flujo de tokens de actualización en Micronaut que use el token generado por un IdP externo, debe interceptar la respuesta de autenticación para extraer el token de actualización y usar la biblioteca auth0/java-jwt para ejecutar automáticamente el flujo completo de tokens de actualización en sus métodos de controlador.

Comments are closed.