Skip to content

Patrones de Implementación BFF

Este documento materializa el Token Handler Pattern (presentado en los Diagramas de Secuencia) en implementaciones tangibles dentro de un ecosistema Quarkus + Apache Camel.

Corresponde al diagrama 02_sso_handshake_sequence.puml. El “OAuth2 Agent” es responsable de gobernar el flujo de redirecciones Seguras con el Identity Provider (IdP).

Dos simples interfaces @Path gestionan el punto de entrada y salida:

@Path("/bff/auth")
public class OAuth2AgentResource {
@GET
@Path("/login")
public Response initiateLogin() {
// Genera el desafío PKCE
// Redirige al URL de Autorización del IdP (HTTP 302)
return Response.status(302).location(idpUrl).build();
}
@GET
@Path("/callback")
public Response handleCallback(@QueryParam("code") String code) {
// Valida el Authorization Code y extrae el Payload
// Delega el Exchange a una Ruta Camel si se requiere orquestación (seda:exchange-token)
String sessionId = UUID.randomUUID().toString();
// Construcción Estricta de la Cookie
NewCookie sessionCookie = new NewCookie.Builder("session_id")
.value(sessionId)
.path("/")
.secure(true) // Requiere HTTPS
.httpOnly(true) // Bloquea lectura desde JavaScript en el SPA
.sameSite(NewCookie.SameSite.LAX) // Protección CSRF base
.build();
return Response.status(302).cookie(sessionCookie).location(spaUrl).build();
}
}

Los tokens crudos jamás deben llegar (o “sangrar”) hacia el frontend. Siguiendo el rigor del estándar:

  1. El OAuth2Agent extrae el access_token y refresh_token del IdP.
  2. Una clave simétrica interna (gestionada vía GCP Secret Manager o Vault) encripta este payload empleando algoritmo AES-GCM.
  3. El paquete encriptado se vuelca en la Caché Distribuida (ej. Firestore / Cloud SQL) y se asocia al string aleatorio sessionId.
  4. El sessionId viaja transparentemente e inyectado al navegador como cabecera Set-Cookie (HttpOnly; Secure).

2. OAuth2 Proxy / API Proxy (Intercepción de Peticiones)

Section titled “2. OAuth2 Proxy / API Proxy (Intercepción de Peticiones)”

Corresponde al diagrama 03_bff_token_handling_sequence.puml. El interceptor (Proxy) captura las peticiones nativas en JSON del Frontend, les inyecta el verdadero token re-hidratado y las lanza contra el Servidor de Recursos (Salesforce API).

Constructo Fundamental: Filtros REST y Clientes Declarativos

Section titled “Constructo Fundamental: Filtros REST y Clientes Declarativos”

Debido a que el cometido central del BFF es ser un túnel de paso directo (leer cookie, desencriptar subyacente, re-enviar), el uso de los componentes ContainerRequestFilter y RestClient de JAX-RS resulta ser extremadamente más rápido y purista arquitectónicamente que embutir cada petición a través de un enrutador completo de Apache Camel.

// 1. Filtro Pre-Matching para interceptar tráfico SPA hacia APIs
@Provider
@PreMatching
public class SessionDecryptionFilter implements ContainerRequestFilter {
@Override
public void filter(ContainerRequestContext ctx) {
// 1. Extraer la cookie "session_id"
Cookie sessionCookie = ctx.getCookies().get("session_id");
if (sessionCookie == null) throw new UnauthorizedException();
// 2. Recuperar el paquete cifrado de la Caché Distribuida y desencriptarlo
String plainAccessToken = decryptToken(cacheStore.get(sessionCookie.getValue()));
// 3. Mutar la petición inyectando explícitamente el Bearer Token
ctx.getHeaders().putSingle("Authorization", "Bearer " + plainAccessToken);
}
}
// 2. Cliente REST Declarativo encapsulando la API subyacente
@RegisterRestClient(configKey = "backend-api")
public interface BackendProxyClient {
@GET
@Path("/{path: .*}")
Response forwardRequest(@PathParam("path") String path, @HeaderParam("Authorization") String token);
}

Si un endpoint en concreto requiere coordinación o coreografía (ej: consultar a 3 bases de datos, cruzar un CSV y enriquecer el JSON de salida), solo en esa circunstancia entra en juego Apache Camel. Para todo el proxying CRUD natural, los filtros JAX-RS mantienen un pipeline performante y completamente estandarizado.