EmDash utiliza la autenticación con passkey como su método principal de inicio de sesión. Los passkeys son resistentes al phishing, no requieren contraseñas y funcionan en todos los dispositivos a través de su navegador o administrador de contraseñas.
Más allá de los passkeys, puede agregar proveedores de inicio de sesión conectables — GitHub, Google y Atmosphere (AT Protocol) se incluyen de fábrica, y la misma interfaz de proveedor está abierta para paquetes de terceros. Cualquier proveedor configurado se puede usar para crear la primera cuenta de administrador, iniciar sesión o vincular a un usuario existente.
Para implementaciones de Cloudflare, Cloudflare Access también está disponible como un método de autenticación exclusivo que toma el control de todo el flujo de inicio de sesión.
Cómo funciona
Los passkeys utilizan WebAuthn, un estándar web que crea credenciales de clave pública almacenadas en su dispositivo o sincronizadas a través de su administrador de contraseñas. Cuando inicia sesión, su dispositivo demuestra la posesión de la credencial sin enviar nunca una contraseña a través de la red.
Beneficios de la autenticación con passkey:
- Sin contraseñas para recordar o filtrar
- Resistente al phishing — las credenciales están vinculadas al dominio de su sitio
- Sincronización entre dispositivos — funciona con iCloud Keychain, Google Password Manager, 1Password, etc.
- Inicio de sesión rápido — un toque con biometría o PIN
Configuración del primer usuario
La primera vez que accede al panel de administración, el Asistente de configuración le guía a través de la creación de su cuenta de administrador.
-
Navegue a
http://localhost:4321/_emdash/admin -
Será redirigido al Asistente de configuración. Ingrese:
- Título del sitio — El nombre de su sitio
- Tagline — Una breve descripción
- Email de administrador — Su dirección de correo electrónico
-
Haga clic en Crear sitio para registrar su passkey
-
Su navegador le solicitará que cree un passkey:
- En macOS: Touch ID, contraseña del dispositivo o llave de seguridad
- En Windows: Windows Hello o llave de seguridad
- En móvil: Face ID, huella digital o PIN
-
Una vez registrado su passkey, ha iniciado sesión y será redirigido al panel de administración.
Iniciar sesión
Después de la configuración, volver al panel de administración activa la autenticación con passkey:
-
Visite
/_emdash/admin -
Si no ha iniciado sesión, verá la página de inicio de sesión
-
Haga clic en Iniciar sesión para autenticarse
-
Su navegador solicita su passkey (biometría, PIN o llave de seguridad)
-
Después de la verificación, será redirigido al panel de administración
Enlace mágico como alternativa
Si no puede usar su passkey (por ejemplo, dispositivo perdido), los enlaces mágicos proporcionan una alternativa. Esto requiere que el correo electrónico esté configurado.
-
En la página de inicio de sesión, haga clic en Iniciar sesión con correo electrónico
-
Ingrese su dirección de correo electrónico
-
Revise su bandeja de entrada para obtener un enlace de inicio de sesión
-
Haga clic en el enlace para autenticarse (válido por 15 minutos)
Proveedores de inicio de sesión
Además de los passkeys, EmDash admite proveedores de inicio de sesión conectables que aparecen en la página de inicio de sesión y en el asistente de configuración. Los proveedores de GitHub, Google y Atmosphere se incluyen en la caja; los paquetes de terceros pueden registrar los suyos propios utilizando la misma interfaz.
Los proveedores son aditivos: los passkeys siguen funcionando cuando los proveedores están habilitados, y los usuarios pueden vincular un proveedor a una cuenta existente de solo passkey. El primer usuario también se puede crear a través de cualquier proveedor configurado, por lo que una instalación nueva puede omitir los passkeys por completo si lo prefiere.
Configurar proveedores
Pase proveedores al array authProviders en la integración EmDash. El siguiente ejemplo habilita GitHub, Google y Atmosphere:
import { defineConfig } from "astro/config";
import emdash from "emdash/astro";
import { github } from "emdash/auth/providers/github";
import { google } from "emdash/auth/providers/google";
import { atproto } from "@emdash-cms/auth-atproto";
export default defineConfig({
integrations: [
emdash({
authProviders: [github(), google(), atproto()],
}),
],
});
El orden importa para la página de inicio de sesión: los proveedores se renderizan en el orden en que los enumera, con proveedores compactos de solo botón primero y proveedores que necesitan un formulario personalizado (como Atmosphere, que solicita un identificador) que se muestran después.
GitHub
El siguiente ejemplo habilita el proveedor de GitHub:
import { github } from "emdash/auth/providers/github";
emdash({ authProviders: [github()] });
Establezca credenciales a través de variables de entorno. EmDash verifica primero los nombres con prefijo y recurre a los sin prefijo:
| Variable | Propósito |
|---|---|
EMDASH_OAUTH_GITHUB_CLIENT_ID / GITHUB_CLIENT_ID | ID de cliente de la aplicación OAuth |
EMDASH_OAUTH_GITHUB_CLIENT_SECRET / GITHUB_CLIENT_SECRET | Secreto de la aplicación OAuth |
Configure la URL de devolución de llamada de su aplicación OAuth de GitHub como https://your-site.example.com/_emdash/api/auth/oauth/github/callback.
El siguiente ejemplo habilita el proveedor de Google:
import { google } from "emdash/auth/providers/google";
emdash({ authProviders: [google()] });
Establezca credenciales a través de variables de entorno. EmDash verifica primero los nombres con prefijo y recurre a los sin prefijo:
| Variable | Propósito |
|---|---|
EMDASH_OAUTH_GOOGLE_CLIENT_ID / GOOGLE_CLIENT_ID | ID de cliente de la aplicación OAuth |
EMDASH_OAUTH_GOOGLE_CLIENT_SECRET / GOOGLE_CLIENT_SECRET | Secreto de la aplicación OAuth |
Configure el URI de redirección de su cliente OAuth de Google como https://your-site.example.com/_emdash/api/auth/oauth/google/callback.
Atmosphere (AT Protocol)
Para sitios donde los colaboradores ya tienen una cuenta Atmosphere — la identidad propiedad del usuario detrás de Bluesky y la red AT Protocol más amplia — instale el proveedor Atmosphere:
pnpm add @emdash-cms/auth-atproto
El siguiente ejemplo habilita el proveedor Atmosphere con una lista de identificadores permitidos:
import { atproto } from "@emdash-cms/auth-atproto";
emdash({
authProviders: [
atproto({
allowedHandles: ["*.example.com"],
}),
],
});
No se necesita secreto de cliente ni variable de entorno. Consulte la guía de inicio de sesión de Atmosphere para listas de identificadores/DID permitidos, mapeo de roles y la configuración de desarrollo local que requiere el perfil OAuth del Protocolo AT.
Crear su propio proveedor
Un proveedor es solo un AuthProviderDescriptor — un id, una etiqueta legible y cualquier combinación de componentes React del lado del administrador, manejadores de rutas, prefijos de rutas públicas y colecciones de almacenamiento. La forma se exporta desde emdash:
import type { AuthProviderDescriptor } from "emdash";
export function myProvider(): AuthProviderDescriptor {
return {
id: "my-provider",
label: "My Provider",
adminEntry: "my-provider/admin", // exports LoginButton / LoginForm / SetupStep
routes: [
{ pattern: "/_emdash/api/auth/my-provider/login", entrypoint: "my-provider/routes/login.ts" },
{ pattern: "/_emdash/api/auth/my-provider/callback", entrypoint: "my-provider/routes/callback.ts" },
],
publicRoutes: ["/_emdash/api/auth/my-provider/"],
storage: {
sessions: {},
},
};
}
El paquete Atmosphere (@emdash-cms/auth-atproto) es la referencia del mundo real más completa para un proveedor que necesita un formulario de inicio de sesión personalizado, manejadores de rutas OAuth y almacenamiento persistente.
Roles de usuario
EmDash utiliza control de acceso basado en roles con cinco niveles:
| Rol | Nivel | Descripción |
|---|---|---|
| Subscriber | 10 | Leer contenido publicado (sin acceso a borradores) |
| Contributor | 20 | Crear contenido (necesita aprobación para publicar) |
| Author | 30 | Crear/editar/publicar su propio contenido |
| Editor | 40 | Gestionar todo el contenido |
| Admin | 50 | Acceso completo incluyendo configuración |
Cada rol hereda permisos de todos los niveles inferiores. El primer usuario siempre se crea como Admin.
Suscriptores y contenido borrador
Los suscriptores tienen el permiso content:read para que el contenido publicado solo para miembros pueda ser servido a lectores autenticados. No pueden ver borradores, elementos programados, elementos en la papelera, revisiones o URLs de vista previa — estos están protegidos por content:read_drafts, otorgado a Contributor y superior. Los endpoints de lista y obtención filtran transparentemente a status=published para Suscriptores; las vistas solo para editores (/compare, /revisions, /trash, /preview-url) rechazan las solicitudes de Suscriptores directamente.
Invitar usuarios
Los administradores pueden invitar nuevos usuarios a través del panel de administración:
-
Vaya a Configuración > Usuarios
-
Haga clic en Invitar usuario
-
Ingrese el correo electrónico del usuario y seleccione un rol
-
Haga clic en Enviar invitación
-
El usuario recibe un correo electrónico con un enlace de invitación
-
Hacen clic en el enlace y registran su passkey
Las invitaciones son válidas durante 7 días. Los administradores pueden reenviar o revocar invitaciones desde la página de Usuarios.
Gestionar passkeys
Los usuarios pueden gestionar sus passkeys desde la configuración de la cuenta:
- Agregar passkey — Registrar passkeys adicionales para respaldo u otros dispositivos
- Eliminar passkey — Eliminar passkeys que ya no usa
- Renombrar passkey — Dar nombres descriptivos a los passkeys
Cada usuario puede tener hasta 10 passkeys registrados.
Permitir que un grupo inicie sesión sin invitaciones
Para permitir que un grupo inicie sesión sin invitar a cada usuario, configure un proveedor de inicio de sesión con una lista de permitidos. El proveedor Atmosphere acepta allowedHandles y allowedDIDs (consulte inicio de sesión Atmosphere); el adaptador Cloudflare Access aprovisiona usuarios de su proveedor de identidad a través de autoProvision y roleMapping. Cualquier proveedor configurado también puede crear la cuenta de administrador inicial.
Sesiones
Las sesiones utilizan cookies seguras, HttpOnly, SameSite=Lax y duran 30 días con expiración deslizante — la expiración se restablece con la actividad.
Notas de seguridad
- Los passkeys se almacenan como claves públicas — la clave privada nunca sale de su dispositivo
- Verificación de desafío previene ataques de repetición
- Limitación de velocidad protege contra fuerza bruta (5 intentos/minuto/IP)
- Las sesiones son HttpOnly, Secure, SameSite=Lax para la seguridad de las cookies
- Los tokens de enlace mágico se cifran con SHA-256 — los tokens sin procesar nunca se almacenan
Solución de problemas
”No hay passkeys registrados”
Si ve este error al iniciar sesión, su passkey puede haber sido eliminado de su administrador de contraseñas. Pídale a un administrador que le envíe un enlace mágico o una nueva invitación.
”Falló la autenticación con passkey”
Esto generalmente significa que el passkey se creó para un dominio diferente. Los passkeys están vinculados al dominio — un passkey para localhost:4321 no funcionará en example.com. Registre un nuevo passkey para cada dominio.
”Sesión expirada”
Las sesiones duran 30 días de forma predeterminada con expiración deslizante. Si cierra sesión inesperadamente, borre sus cookies e inicie sesión nuevamente.
Perdí todos los passkeys
Si ha perdido el acceso a todos sus passkeys registrados:
- Pídale a otro administrador que le envíe un enlace mágico (requiere configuración de correo electrónico)
- Use el enlace mágico para iniciar sesión
- Registre un nuevo passkey en la configuración de la cuenta
Si usted es el único administrador y el correo electrónico no está configurado, deberá restablecer la autenticación de su sitio a través de la base de datos.
Cloudflare Access
Al implementar en Cloudflare, puede usar Cloudflare Access como su proveedor de autenticación en lugar de passkeys. Access maneja la autenticación en el edge utilizando su proveedor de identidad existente.
Por qué usar Cloudflare Access
- Single Sign-On — Los usuarios se autentican con el IdP de su empresa
- Control de acceso centralizado — Administre quién puede acceder al admin en el panel de Cloudflare
- Sin gestión de passkeys — No es necesario registrar o administrar passkeys
- Roles basados en grupos — Mapee grupos de IdP a roles de EmDash automáticamente
Configuración
- Cree una aplicación Cloudflare Access para su sitio EmDash
- Anote la Application Audience (AUD) Tag de la configuración de la aplicación
- Configure EmDash para usar Access:
import { defineConfig } from "astro/config";
import cloudflare from "@astrojs/cloudflare";
import emdash from "emdash/astro";
import { d1, access } from "@emdash-cms/cloudflare";
export default defineConfig({
output: "server",
adapter: cloudflare(),
integrations: [
emdash({
database: d1({ binding: "DB" }),
auth: access({
teamDomain: "myteam.cloudflareaccess.com",
audience: "abc123def456...", // From Access app settings
}),
}),
],
});
Opciones de configuración
| Opción | Tipo | Predeterminado | Descripción |
|---|---|---|---|
teamDomain | string | requerido | Su dominio de equipo de Access (por ejemplo, myteam.cloudflareaccess.com) |
audience | string | requerido | Etiqueta Application Audience (AUD) de la configuración de Access |
autoProvision | boolean | true | Crear usuarios de EmDash en el primer inicio de sesión de Access |
defaultRole | number | 30 | Rol para usuarios que no coinciden con ningún grupo (30 = Author) |
syncRoles | boolean | false | Actualizar rol en cada inicio de sesión según grupos de IdP |
roleMapping | object | — | Mapear nombres de grupos de IdP a niveles de roles |
audienceEnvVar | string | "CF_ACCESS_AUDIENCE" | Nombre de variable de entorno para la etiqueta de audiencia (alternativa a la codificación fija) |
Mapeo de roles
Mapee sus grupos de IdP a roles de EmDash:
emdash({
auth: access({
teamDomain: "myteam.cloudflareaccess.com",
audience: "abc123...",
roleMapping: {
Admins: 50, // Admin
"Content Editors": 40, // Editor
Writers: 30, // Author
},
defaultRole: 20, // Contributor para usuarios que no están en ningún grupo
}),
});
El primer grupo coincidente gana si un usuario pertenece a múltiples grupos. El primer usuario en acceder al sitio siempre se convierte en Admin, independientemente de los grupos.
Comportamiento de sincronización de roles
De forma predeterminada (syncRoles: false), el rol de un usuario se establece cuando inicia sesión por primera vez y no cambia después. Esto permite a los administradores ajustar manualmente los roles en EmDash.
Establezca syncRoles: true si desea que los grupos de IdP sean autoritarios — el rol del usuario se actualizará en cada inicio de sesión según sus grupos actuales.
Cómo funciona
- El usuario visita
/_emdash/admin - Cloudflare Access intercepta y redirige a su IdP
- El usuario se autentica (SSO, MFA, etc.)
- Access establece un JWT firmado en la solicitud
- EmDash valida el JWT y crea/autentica al usuario
Funciones deshabilitadas
Cuando Access está habilitado, estas funciones no están disponibles:
- Página de inicio de sesión (
/_emdash/admin/login) - Registro y gestión de passkeys
- Inicio de sesión OAuth
- Inicio de sesión con enlace mágico
- Auto-registro
- Invitaciones de usuarios
La gestión de usuarios se realiza completamente a través de sus políticas de Cloudflare Access.
Solución de problemas
”No hay JWT de Access presente”
La solicitud llegó a EmDash sin un JWT de Access. Esto significa:
- Access no está configurado para proteger su aplicación
- La política de Access no coincide con las rutas del administrador
Verifique que su aplicación de Access cubra /_emdash/admin/*.
”Desajuste de audiencia JWT”
La audience en su configuración no coincide con el JWT. Verifique la Application Audience Tag en la configuración de su aplicación de Access.
”Usuario no autorizado”
El usuario se autenticó a través de Access pero autoProvision es false y no existen en EmDash. O bien:
- Establezca
autoProvision: true, o - Cree el usuario manualmente antes de que inicie sesión