EmDash usa la autenticación con passkeys como método de inicio de sesión principal. Las 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 las passkeys, puede añadir proveedores de inicio de sesión enchufables. GitHub y Google están incluidos con EmDash. El proveedor Atmosphere instalado por separado añade cuentas AT Protocol, y la misma interfaz de proveedor está abierta a otros paquetes. Los proveedores documentados de GitHub, Google y Atmosphere pueden crear la primera cuenta de administrador o iniciar sesión de un usuario EmDash vinculado.
En implementaciones de Cloudflare, Cloudflare Access es un modo de autenticación separado y exclusivo en producción. Valida las credenciales de Access en las rutas EmDash protegidas en lugar de mostrar los métodos de inicio de sesión de EmDash.
Elegir un modo de autenticación
Las passkeys usan 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. Al iniciar sesión, su dispositivo demuestra la posesión de la credencial sin enviar nunca una contraseña por la red.
Las passkeys son el valor predeterminado. Los proveedores de GitHub, Google y Atmosphere son métodos de inicio de sesión adicionales: cada uno autentica al usuario, vincula o crea una cuenta EmDash y establece la misma sesión EmDash que usa un inicio de sesión con passkey.
La autenticación con passkeys proporciona:
- Sin contraseñas que 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
Cloudflare Access usa la opción auth en lugar de authProviders. En producción se convierte en la autoridad de las rutas /_emdash protegidas. EmDash sigue almacenando un usuario local para que los roles, la propiedad y las comprobaciones de usuarios deshabilitados sigan funcionando.
Configurar el primer usuario
La primera vez que accede al panel de administración, el asistente de configuración le guía para crear su cuenta de administrador.
-
Vaya a
http://localhost:4321/_emdash/admin -
En Set up your site, introduzca el título del sitio y un eslogan opcional. Una plantilla también puede ofrecer contenido de ejemplo. Seleccione Continue.
-
En Create your account, introduzca su dirección de correo y un nombre opcional. Seleccione Continue.
-
En Secure your account, cree una passkey o elija uno de los proveedores de inicio de sesión configurados. Si elige una passkey, su navegador pregunta dónde guardarla:
- 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 o PIN
-
Complete el flujo del navegador o del proveedor. EmDash crea el primer usuario como Admin y abre el panel.
Iniciar sesión con una passkey
Tras 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 Sign in para autenticarse
-
Su navegador solicita su passkey (biometría, PIN o llave de seguridad)
-
Tras la verificación, se le redirige al panel de administración
Iniciar sesión con un magic link
Si no puede usar su passkey, un magic link ofrece una alternativa. El sitio debe tener un proveedor de correo configurado antes de que EmDash pueda enviar el enlace — consulte Configuración de correo.
-
En la página de inicio de sesión, haga clic en Sign in with email
-
Introduzca su dirección de correo
-
Revise su bandeja de entrada para un enlace de inicio de sesión
-
Haga clic en el enlace (válido durante 15 minutos) y luego seleccione Continue en la página de confirmación
El enlace solo se usa cuando selecciona Continue, de modo que los escáneres de seguridad de correo que abren enlaces por adelantado no lo agotan.
Configurar proveedores de inicio de sesión
Además de las passkeys, EmDash admite proveedores de inicio de sesión enchufables que aparecen en la página de inicio de sesión y en el asistente de configuración. GitHub y Google están incluidos con EmDash. Atmosphere y los proveedores de terceros son paquetes separados que se registran a través de la misma interfaz.
Los proveedores son aditivos: las passkeys siguen funcionando cuando hay proveedores habilitados. GitHub y Google vinculan automáticamente un usuario EmDash existente solo cuando el proveedor suministra la misma dirección de correo verificada. Las cuentas Atmosphere se vinculan por su identificador descentralizado (DID), porque el flujo Atmosphere de EmDash no recibe una dirección de correo. Cada proveedor incluido puede crear el primer usuario, de modo que una instalación nueva puede omitir las passkeys por completo.
Añadir proveedores a Astro
Pase los proveedores al array authProviders de 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 en la página de inicio de sesión: los proveedores se renderizan en el orden en que los enumera, con los proveedores compactos solo de botón primero y los proveedores que necesitan un formulario personalizado (como Atmosphere, que pide un handle) después.
GitHub
El siguiente ejemplo habilita el proveedor de GitHub:
import { github } from "emdash/auth/providers/github";
emdash({ authProviders: [github()] });
Establezca las credenciales mediante variables de entorno. EmDash comprueba primero los nombres con prefijo y recurre a los sin prefijo:
| Variable | Purpose |
|---|---|
EMDASH_OAUTH_GITHUB_CLIENT_ID / GITHUB_CLIENT_ID | ID de cliente de la app OAuth |
EMDASH_OAUTH_GITHUB_CLIENT_SECRET / GITHUB_CLIENT_SECRET | Secreto de la app OAuth |
Configure la URL de callback de su app 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 las credenciales mediante variables de entorno. EmDash comprueba primero los nombres con prefijo y recurre a los sin prefijo:
| Variable | Purpose |
|---|---|
EMDASH_OAUTH_GOOGLE_CLIENT_ID / GOOGLE_CLIENT_ID | ID de cliente de la app OAuth |
EMDASH_OAUTH_GOOGLE_CLIENT_SECRET / GOOGLE_CLIENT_SECRET | Secreto de la app 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 cuyos colaboradores ya tienen una cuenta Atmosphere — la identidad propiedad del usuario detrás de Bluesky y la red más amplia de AT Protocol — instale el proveedor Atmosphere:
pnpm add @emdash-cms/auth-atproto
El siguiente ejemplo habilita el proveedor Atmosphere con una lista de handles 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 Atmosphere para listas de handles/DID permitidos, asignación de roles y la configuración de desarrollo local que exige el perfil OAuth de AT Protocol.
Crear un proveedor
Un proveedor es un AuthProviderDescriptor: un id, una etiqueta legible y los componentes de administración, manejadores de rutas, prefijos de rutas públicas y colecciones de almacenamiento que necesita su flujo de inicio de sesión. Exporte un SetupStep desde adminEntry si el proveedor debe aparecer durante la configuración del primer usuario. 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 real más completa de un proveedor que necesita un formulario de inicio de sesión personalizado, manejadores de rutas OAuth y almacenamiento persistente.
Roles de usuario
EmDash usa control de acceso basado en roles con cinco niveles:
| Role | Level | Description |
|---|---|---|
| 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, incluida la configuración |
Cada rol hereda permisos de todos los niveles inferiores. El primer usuario siempre se crea como Admin.
Suscriptores y contenido en borrador
Los suscriptores tienen el permiso content:read para que el contenido publicado solo para miembros se pueda servir a lectores autenticados. No pueden ver borradores, elementos programados, elementos en la papelera, revisiones ni URLs de vista previa: eso se controla con content:read_drafts, concedido a Contributor y superiores. Los endpoints de lista y obtención filtran de forma transparente a status=published para Suscriptores; las vistas solo de editor (/compare, /revisions, /trash, /preview-url) rechazan de plano las solicitudes de Suscriptores.
Invitar usuarios
Los administradores pueden invitar a nuevos usuarios desde el panel de administración:
-
Vaya a Settings > Users
-
Haga clic en Invite User
-
Introduzca el correo del usuario y seleccione un rol
-
Haga clic en Send Invite
-
Si el correo está configurado, EmDash envía la invitación. En caso contrario, copie el enlace generado y envíelo usted mismo al usuario.
-
Abren el enlace y crean la cuenta con una passkey o un proveedor de inicio de sesión ofrecido en la página de invitación.
Los enlaces de invitación son de un solo uso y caducan a los 7 días.
Gestionar passkeys
Los usuarios pueden gestionar sus passkeys desde la configuración de la cuenta:
- Add passkey — Registrar passkeys adicionales como respaldo u otros dispositivos
- Remove passkey — Eliminar passkeys que ya no usa
- Rename passkey — Dar a las passkeys nombres descriptivos
Cada usuario puede tener hasta 10 passkeys registradas.
EmDash no permite que un usuario elimine su última passkey. Añada un reemplazo antes de eliminar la antigua.
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 (vea Inicio de sesión Atmosphere); el adaptador de Cloudflare Access aprovisiona usuarios desde su proveedor de identidad mediante autoProvision y roleMapping. Los proveedores documentados de GitHub, Google y Atmosphere también pueden crear la cuenta de administrador inicial.
Sesiones
Los callbacks de passkey, magic link, invitación y proveedor de inicio de sesión almacenan el ID de usuario EmDash en el almacén de sesiones de Astro. El navegador recibe el identificador opaco astro-session de Astro; los registros de usuario y credenciales permanecen en la base de datos de EmDash.
Cloudflare Access también escribe el usuario EmDash resuelto en la sesión de Astro. Eso permite que las páginas públicas identifiquen a un usuario con sesión iniciada cuando leen Astro.locals.user. La sesión no sustituye la autenticación de Access en las rutas /_emdash protegidas: EmDash valida de nuevo el JSON Web Token (JWT) de Access en esas solicitudes.
Límites de tasa de autenticación
EmDash limita los endpoints que inician flujos de inicio de sesión o registro no autenticados. Los límites son independientes para cada endpoint e IP de cliente de confianza:
| Endpoint | Limit |
|---|---|
POST /_emdash/api/auth/passkey/options | 10 solicitudes por minuto |
POST /_emdash/api/auth/magic-link/send | 3 solicitudes por 5 minutos |
POST /_emdash/api/auth/signup/request | 3 solicitudes por 5 minutos |
En Cloudflare, EmDash lee la IP del cliente de los metadatos de solicitud de Cloudflare. Un sitio autoalojado detrás de un proxy inverso debe configurar trustedProxyHeaders antes de que EmDash pueda usar el encabezado de IP del cliente del proxy. Cuando no hay IP de confianza disponible, estas comprobaciones por IP se omiten porque no hay una clave segura con la que contar.
Las passkeys almacenan credenciales de clave pública; la clave privada permanece con el autenticador del usuario. Los tokens de magic link se almacenan como hashes SHA-256 y se eliminan tras su uso.
Solución de problemas
”No passkeys registered”
Si ve este error al iniciar sesión, es posible que su passkey se haya eliminado de su administrador de contraseñas. Pida a un administrador que envíe un magic link de recuperación; el sitio debe tener el correo configurado.
”Passkey authentication failed”
Esto suele significar que la passkey se creó para un dominio diferente. Las passkeys están vinculadas al dominio: una passkey para localhost:4321 no funcionará en example.com. Registre una passkey nueva para cada dominio.
Se perdieron todas las passkeys
Si ha perdido el acceso a todas sus passkeys registradas:
- Pida a otro administrador que envíe un magic link de recuperación. El sitio debe tener el correo configurado.
- Abra el enlace en un plazo de 15 minutos y seleccione Continue para iniciar sesión.
- Registre una passkey nueva en la configuración de la cuenta.
Si es el único administrador y el correo no está configurado, tendrá que restablecer la autenticación del sitio a través de la base de datos.
Cloudflare Access
Al implementar en Cloudflare, puede usar Cloudflare Access en lugar de los métodos de inicio de sesión integrados. Access autentica al usuario en el edge con su proveedor de identidad. EmDash valida el JWT de Access firmado, carga la identidad y los grupos de la persona, y asigna esa identidad a un usuario EmDash local.
Cuándo usar Cloudflare Access
- Inicio de sesión único (SSO) — Los usuarios se autentican con el IdP de su empresa
- Control de acceso centralizado — Gestione quién puede acceder a la administración en el panel de Cloudflare
- Sin gestión de passkeys — No es necesario registrar ni gestionar passkeys
- Roles basados en grupos — Asigne grupos del IdP a roles de EmDash automáticamente
Configurar Access
- Cree una aplicación y una política de Cloudflare Access para la ruta
/_emdash/*de su sitio. Proteger solo/_emdash/admin/*deja la API REST sin el JWT que EmDash espera. - Copie la Application Audience (AUD) Tag de la aplicación.
- Guarde la etiqueta en la variable de entorno en tiempo de ejecución
CF_ACCESS_AUDIENCE. Siga la guía de secretos de EmDash para valores locales e implementados. - Configure EmDash para leer ese valor en tiempo de ejecución:
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",
audienceEnvVar: "CF_ACCESS_AUDIENCE",
}),
}),
],
});
La audiencia de la aplicación identifica qué aplicación Access emitió el JWT. EmDash la verifica junto con el emisor y la firma; se rechaza un token de otra aplicación Access.
Opciones de configuración
| Option | Type | Default | Description |
|---|---|---|---|
teamDomain | string | required | Su dominio de equipo Access (p. ej., myteam.cloudflareaccess.com) |
audience | string | — | Application Audience (AUD) Tag suministrado directamente. Prefiera audienceEnvVar en Workers. |
autoProvision | boolean | true | Crear usuarios 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 el rol en cada inicio de sesión según los grupos del IdP |
roleMapping | object | — | Asignar nombres de grupos del IdP a niveles de rol |
audienceEnvVar | string | "CF_ACCESS_AUDIENCE" | Variable de entorno que contiene la etiqueta de audiencia. Se usa cuando se omite audience. |
Proporcione audience o un valor de entorno bajo audienceEnvVar.
Asignación de roles
Asigne sus grupos del IdP a roles de EmDash:
emdash({
auth: access({
teamDomain: "myteam.cloudflareaccess.com",
audienceEnvVar: "CF_ACCESS_AUDIENCE",
roleMapping: {
Admins: 50, // Admin
"Content Editors": 40, // Editor
Writers: 30, // Author
},
defaultRole: 20, // Contributor for users not in any group
}),
});
El primer grupo coincidente gana si un usuario pertenece a varios grupos. El primer usuario que accede al sitio siempre se convierte en Admin, independientemente de los grupos.
Comportamiento de sincronización de roles
Por defecto (syncRoles: false), el rol de un usuario se establece en el primer inicio de sesión y no cambia después. Esto permite a los administradores ajustar roles manualmente en EmDash.
Establezca syncRoles: true si quiere que los grupos del IdP sean autoritativos: el rol del usuario se actualizará en cada inicio de sesión según sus grupos actuales.
Flujo de solicitud y sesión
- El usuario visita una ruta protegida por la aplicación Access.
- Cloudflare Access redirige al usuario a su proveedor de identidad cuando no existe una sesión Access.
- Tras la autenticación, Access envía un JWT firmado al origen en
Cf-Access-Jwt-Assertion. - EmDash valida la firma, el emisor y la audiencia del token, y luego lee la identidad y los grupos de Access.
- EmDash encuentra o aprovisiona al usuario local, aplica el comportamiento de rol configurado y registra al usuario en la sesión de Astro.
- Las solicitudes posteriores a rutas EmDash protegidas repiten la validación de Access. Las páginas públicas pueden usar la sesión EmDash para identificar al usuario sin tratarla como prueba de una nueva solicitud Access.
Funciones sustituidas por Access
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 con GitHub, Google y Atmosphere
- Inicio de sesión con magic link
- Autoregistro
- Invitaciones de usuario
Las políticas de Access deciden quién llega a EmDash. EmDash sigue siendo dueño de los roles locales, la propiedad del contenido y el indicador de usuario deshabilitado. Con syncRoles: false, los administradores pueden cambiar el rol de un usuario aprovisionado en EmDash. Con syncRoles: true, los grupos Access asignados sustituyen ese rol en cada inicio de sesión.
Solución de problemas
”No Access JWT present”
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 de administración
Verifique que la aplicación Access cubre la ruta completa /_emdash/* y que su política incluye al usuario.
”JWT audience mismatch”
La audience de su configuración no coincide con el JWT. Compruebe de nuevo la Application Audience Tag en la configuración de su aplicación Access.
”User not authorized”
El usuario se autenticó mediante Access pero autoProvision es false y no existe en EmDash. O bien:
- Establezca
autoProvision: true, o - Cree el usuario manualmente antes de que inicie sesión