Autenticación de miembros
Autentica a los miembros del sitio con sesiones seguras en cookies httpOnly - inicio de sesión, registro, restablecimiento de contraseña, lectura del miembro actual y uso de auth desde un bloque.
Resumen
Los miembros del sitio son los usuarios finales de tu sitio web publicado - completamente separados de los usuarios admin del CMS. Cada workspace mantiene su propia base de miembros (multi-tenant). El SDK emite las sesiones de miembros como cookies httpOnly (cmssy_session, un JWE sellado), de modo que el token nunca es legible desde JavaScript y nunca toca tu código cliente. El SDK gestiona el sellado, el refresco y el intercambio Authorization: Bearer en el servidor.
1. Configurar
Añade un bloque auth a tu configuración. Es opcional - si lo omites, la auth de miembros simplemente queda desactivada (context.auth es undefined y los bloques se renderizan como no autenticados).
// cmssy.config.ts
export const cmssy: CmssyNextConfig = {
// ...
auth: {
modelSlug: "members", // the member model in your workspace
sessionSecret: process.env.CMSSY_SESSION_SECRET!, // >= 32 chars
},
};2. Montar la ruta de auth
Un único handler de ruta impulsa todo el flujo. Las credenciales y los tokens se manejan solo aquí, en el servidor - los clientes solo envían POST.
// app/api/auth/[action]/route.ts
import { createCmssyAuthRoute } from "@cmssy/next";
import { cmssy } from "@/cmssy.config";
export const { POST, GET } = createCmssyAuthRoute(cmssy);| Método + acción | Body | Efecto |
|---|---|---|
POST /api/auth/sign-in | { identity, password } | Establece la cookie de sesión. |
POST /api/auth/register | { identity, password, fields } | Crea un miembro. |
POST /api/auth/sign-out | - | Borra la sesión. |
POST /api/auth/sign-out-everywhere | - | Revoca todas las sesiones. |
POST /api/auth/refresh | - | Rota los tokens. |
POST /api/auth/forgot-password | { identity } | Envía un email de restablecimiento. |
POST /api/auth/reset-password | { token, newPassword } | Restablece una contraseña. |
POST /api/auth/verify-email | { token } | Verifica un email. |
GET /api/auth/me | - | Devuelve { user } o { user: null }. |
Cada acción devuelve JSON { ok: boolean, message?, user? }.
3. Refrescar sesiones en el middleware
// middleware.ts
import { createCmssyAuthMiddleware } from "@cmssy/next";
import { cmssy } from "@/cmssy.config";
export const middleware = createCmssyAuthMiddleware(cmssy);Esto refresca de forma transparente una cookie de sesión a punto de expirar durante la navegación, así los miembros permanecen conectados sin ningún manejo de tokens en el cliente.
4. Flujo de auth en el cliente
Tus interfaces de login, registro y logout son componentes cliente normales que envían POST a la ruta. Nunca ven un token - la ruta establece la cookie.
"use client";
// sign in
await fetch("/api/auth/sign-in", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ identity: email, password }),
});
// the route set the cookie - now redirect
window.location.href = "/";
// log out
await fetch("/api/auth/sign-out", { method: "POST" });Crea páginas dedicadas para el flujo: /login, /register, /forgot-password, /reset-password, /verify-email. Cada una es un pequeño componente cliente que envía un POST a /api/auth/* y luego redirige.
5. Leer el miembro actual (en el servidor)
import { getCmssyUser, getCmssyAccessToken } from "@cmssy/next";
import { cmssy } from "@/cmssy.config";
const user = await getCmssyUser(cmssy); // { recordId, email } | null
const token = await getCmssyAccessToken(cmssy); // bearer token | null6. Leer auth dentro de un bloque
Cuando config.auth está definido, createCmssyPage resuelve el miembro en el servidor y lo inyecta en el contexto del bloque como context.auth - solo datos:
context.auth;
// { isAuthenticated: boolean; member: { recordId, email } | null } | undefinedimport type { CmssyBlockAuthContext } from "@cmssy/react";
function AccountBadge({ context }: { context?: { auth?: CmssyBlockAuthContext } }) {
if (!context?.auth?.isAuthenticated) return <a href="/login">Sign in</a>;
return <span>{context.auth.member?.email}</span>;
}No hay funciones login/logout en context.auth - las funciones no pueden cruzar la frontera servidor-cliente hacia un bloque cliente. Iniciar sesión, cerrarla y registrarse pasan por los POST del cliente del paso 4.
7. Peticiones autenticadas de miembro
Una mutación con ámbito de miembro (p. ej. actualizar un perfil) necesita el token de acceso, que vive en la cookie httpOnly y es ilegible desde el JS del cliente por diseño. No intentes adjuntarlo en el cliente. Llámala desde un handler de ruta o una server action que lea el token y lo reenvíe como Authorization: Bearer:
// app/api/member-graphql/route.ts
import { getCmssyAccessToken } from "@cmssy/next";
import { cmssy } from "@/cmssy.config";
export async function POST(request: Request) {
const token = await getCmssyAccessToken(cmssy);
if (!token) {
return Response.json({ errors: [{ message: "Not authenticated" }] }, { status: 401 });
}
const upstream = await fetch(cmssy.apiUrl, {
method: "POST",
headers: { "content-type": "application/json", authorization: `Bearer ${token}` },
body: JSON.stringify(await request.json()),
});
return Response.json(await upstream.json(), { status: upstream.status });
}Tu bloque cliente envía entonces las mutaciones de miembro por POST a /api/member-graphql en lugar del endpoint público, y el token nunca llega al navegador.
Antipatrón
// DON'T - XSS-readable, and bypasses the secure cookie flow entirely
localStorage.setItem("member_token", accessToken);Pasa siempre por createCmssyAuthRoute + la cookie httpOnly.
Roles de miembros
Roles por defecto: Guest, Member (asignado al registrarse), Premium. Los roles personalizados son configurables por workspace.
Flujo de verificación de email
- Registro -> estado pending, se envía un email de verificación.
- Clic en el enlace ->
/verify-email?token=...-> estado active. - Cuando la verificación de email es obligatoria, el inicio de sesión queda bloqueado hasta que el miembro esté verificado.
Flujo de restablecimiento de contraseña
- Formulario de contraseña olvidada -> se envía un email de restablecimiento.
- Clic en el enlace ->
/reset-password?token=...-> establece una nueva contraseña. - Los tokens de restablecimiento expiran tras 1 hora.
Sesiones
La sesión es un JWE sellado en la cookie httpOnly cmssy_session. El middleware la rota de forma transparente cuando se acerca su expiración - tu código nunca lee ni refresca un token a mano. Todos los datos de miembros están acotados al workspace (seguro en multi-tenant).