Skip to content

Patrones de Implementación BFF

Este documento materializa el Token Handler Pattern (presentado en SSO y Token Handler Pattern) en implementaciones tangibles dentro de un ecosistema Quarkus.

Para las decisiones de plataforma que justifican este stack, véase Decisiones Tecnológicas.

El “OAuth2 Agent” es responsable de gobernar el flujo de redirecciones seguras con el Identity Provider (IdP) de Salesforce siguiendo el estándar Authorization Code + PKCE (RFC 7636).

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 (code_verifier + code_challenge)
// 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 al Session Store (cifrado + persistencia)
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();
}
}

Referencia: NewCookie API · SameSite cookies (MDN).

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 HashiCorp Vault) encripta este payload empleando algoritmo AES-GCM (autenticado y seguro frente a manipulación).
  3. El paquete encriptado se vuelca en la Caché Distribuida (ej. Cloud Firestore o Cloud SQL / PostgreSQL) y se asocia al string aleatorio sessionId.
  4. El sessionId viaja transparentemente e inyectado al navegador como cabecera Set-Cookie (HttpOnly; Secure).

La elección del Session Store (Firestore vs. RDBMS) se describe en Gestión de Estado (Sesión).

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

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

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). Véase la secuencia completa en Resolución de Peticiones y Token Exchange.

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 ContainerRequestFilter y @RegisterRestClient de JAX-RS / Quarkus 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);
}

Referencias: @PreMatching · Quarkus REST Client Guide · Bearer Token (RFC 6750).