EmDash utilise l’authentification par passkeys comme méthode de connexion principale. Les passkeys résistent au phishing, ne nécessitent pas de mots de passe et fonctionnent sur tous les appareils via votre navigateur ou gestionnaire de mots de passe.
Au-delà des passkeys, vous pouvez ajouter des fournisseurs de connexion enfichables. GitHub et Google sont inclus avec EmDash. Le fournisseur Atmosphere installé séparément ajoute les comptes AT Protocol, et la même interface de fournisseur est ouverte aux autres paquets. Les fournisseurs documentés GitHub, Google et Atmosphere peuvent créer le premier compte administrateur ou connecter un utilisateur EmDash lié.
Pour les déploiements Cloudflare, Cloudflare Access est un mode d’authentification distinct et exclusif en production. Il valide les identifiants Access sur les routes EmDash protégées plutôt que d’afficher les méthodes de connexion EmDash.
Choisir un mode d’authentification
Les passkeys utilisent WebAuthn, une norme web qui crée des identifiants à clé publique stockés sur votre appareil ou synchronisés via votre gestionnaire de mots de passe. Lors de la connexion, votre appareil prouve la possession de l’identifiant sans jamais envoyer de mot de passe sur le réseau.
Les passkeys sont le mode par défaut. Les fournisseurs GitHub, Google et Atmosphere sont des méthodes de connexion supplémentaires : chacune authentifie l’utilisateur, lie ou crée un compte EmDash, et établit la même session EmDash qu’une connexion par passkey.
L’authentification par passkeys offre :
- Aucun mot de passe à mémoriser ou à fuiter
- Résistant au phishing — les identifiants sont liés au domaine de votre site
- Synchronisation multi-appareils — fonctionne avec iCloud Keychain, Google Password Manager, 1Password, etc.
- Connexion rapide — un appui avec biométrie ou PIN
Cloudflare Access utilise l’option auth au lieu de authProviders. En production, il devient l’autorité pour les routes /_emdash protégées. EmDash stocke toujours un utilisateur local afin que les rôles, la propriété et les contrôles d’utilisateurs désactivés continuent de fonctionner.
Configurer le premier utilisateur
La première fois que vous accédez au panneau d’administration, l’assistant de configuration vous guide pour créer votre compte administrateur.
-
Accédez à
http://localhost:4321/_emdash/admin -
Sur Set up your site, saisissez le titre du site et un slogan facultatif. Un modèle peut aussi proposer du contenu d’exemple. Sélectionnez Continue.
-
Sur Create your account, saisissez votre adresse e-mail et un nom facultatif. Sélectionnez Continue.
-
Sur Secure your account, créez une passkey ou choisissez l’un des fournisseurs de connexion configurés. Si vous choisissez une passkey, votre navigateur demande où l’enregistrer :
- Sur macOS : Touch ID, mot de passe de l’appareil ou clé de sécurité
- Sur Windows : Windows Hello ou clé de sécurité
- Sur mobile : Face ID, empreinte digitale ou PIN
-
Terminez le flux du navigateur ou du fournisseur. EmDash crée le premier utilisateur en tant qu’Admin et ouvre le tableau de bord.
Se connecter avec une passkey
Après la configuration, le retour au panneau d’administration déclenche l’authentification par passkey :
-
Visitez
/_emdash/admin -
Si vous n’êtes pas connecté, vous verrez la page de connexion
-
Cliquez sur Sign in pour vous authentifier
-
Votre navigateur demande votre passkey (biométrie, PIN ou clé de sécurité)
-
Après vérification, vous êtes redirigé vers le tableau de bord d’administration
Se connecter avec un magic link
Si vous ne pouvez pas utiliser votre passkey, un magic link offre une alternative. Le site doit avoir un fournisseur d’e-mail configuré avant qu’EmDash puisse envoyer le lien — voir Configuration de l’e-mail.
-
Sur la page de connexion, cliquez sur Sign in with email
-
Saisissez votre adresse e-mail
-
Vérifiez votre boîte de réception pour un lien de connexion
-
Cliquez sur le lien (valide 15 minutes), puis sélectionnez Continue sur la page de confirmation
Le lien n’est utilisé que lorsque vous sélectionnez Continue, afin que les scanners de sécurité e-mail qui ouvrent les liens à l’avance ne l’épuisent pas.
Configurer les fournisseurs de connexion
En plus des passkeys, EmDash prend en charge des fournisseurs de connexion enfichables qui apparaissent sur la page de connexion et dans l’assistant de configuration. GitHub et Google sont inclus avec EmDash. Atmosphere et les fournisseurs tiers sont des paquets séparés qui s’enregistrent via la même interface.
Les fournisseurs sont additifs : les passkeys continuent de fonctionner lorsque des fournisseurs sont activés. GitHub et Google lient automatiquement un utilisateur EmDash existant uniquement lorsque le fournisseur fournit la même adresse e-mail vérifiée. Les comptes Atmosphere sont liés par leur identifiant décentralisé (DID), car le flux Atmosphere d’EmDash ne reçoit pas d’adresse e-mail. Chaque fournisseur inclus peut créer le premier utilisateur, de sorte qu’une installation neuve peut entièrement ignorer les passkeys.
Ajouter des fournisseurs à Astro
Passez les fournisseurs au tableau authProviders de l’intégration EmDash. L’exemple suivant active GitHub, Google et 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()],
}),
],
});
L’ordre compte pour la page de connexion : les fournisseurs s’affichent dans l’ordre où vous les listez, avec les fournisseurs compacts à bouton uniquement en premier et les fournisseurs qui nécessitent un formulaire personnalisé (comme Atmosphere, qui demande un handle) ensuite.
GitHub
L’exemple suivant active le fournisseur GitHub :
import { github } from "emdash/auth/providers/github";
emdash({ authProviders: [github()] });
Définissez les identifiants via des variables d’environnement. EmDash vérifie d’abord les noms préfixés, puis se rabat sur les noms sans préfixe :
| Variable | Purpose |
|---|---|
EMDASH_OAUTH_GITHUB_CLIENT_ID / GITHUB_CLIENT_ID | ID client de l’app OAuth |
EMDASH_OAUTH_GITHUB_CLIENT_SECRET / GITHUB_CLIENT_SECRET | Secret de l’app OAuth |
Configurez l’URL de callback de votre app OAuth GitHub comme https://your-site.example.com/_emdash/api/auth/oauth/github/callback.
L’exemple suivant active le fournisseur Google :
import { google } from "emdash/auth/providers/google";
emdash({ authProviders: [google()] });
Définissez les identifiants via des variables d’environnement. EmDash vérifie d’abord les noms préfixés, puis se rabat sur les noms sans préfixe :
| Variable | Purpose |
|---|---|
EMDASH_OAUTH_GOOGLE_CLIENT_ID / GOOGLE_CLIENT_ID | ID client de l’app OAuth |
EMDASH_OAUTH_GOOGLE_CLIENT_SECRET / GOOGLE_CLIENT_SECRET | Secret de l’app OAuth |
Configurez l’URI de redirection de votre client OAuth Google comme https://your-site.example.com/_emdash/api/auth/oauth/google/callback.
Atmosphere (AT Protocol)
Pour les sites dont les contributeurs ont déjà un compte Atmosphere — l’identité appartenant à l’utilisateur derrière Bluesky et le réseau AT Protocol plus large — installez le fournisseur Atmosphere :
pnpm add @emdash-cms/auth-atproto
L’exemple suivant active le fournisseur Atmosphere avec une liste de handles autorisés :
import { atproto } from "@emdash-cms/auth-atproto";
emdash({
authProviders: [
atproto({
allowedHandles: ["*.example.com"],
}),
],
});
Aucun secret client ni variable d’environnement n’est nécessaire. Consultez le guide de connexion Atmosphere pour les listes d’autorisation handle/DID, le mapping des rôles et la configuration de développement local exigée par le profil OAuth AT Protocol.
Créer un fournisseur
Un fournisseur est un AuthProviderDescriptor : un id, un libellé lisible, et les composants d’administration, gestionnaires de routes, préfixes de routes publiques et collections de stockage dont son flux de connexion a besoin. Exportez un SetupStep depuis adminEntry si le fournisseur doit apparaître lors de la configuration du premier utilisateur. La forme est exportée depuis 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: {},
},
};
}
Le paquet Atmosphere (@emdash-cms/auth-atproto) est la référence réelle la plus complète pour un fournisseur qui nécessite un formulaire de connexion personnalisé, des gestionnaires de routes OAuth et un stockage persistant.
Rôles utilisateur
EmDash utilise un contrôle d’accès basé sur les rôles avec cinq niveaux :
| Role | Level | Description |
|---|---|---|
| Subscriber | 10 | Lire le contenu publié (pas d’accès aux brouillons) |
| Contributor | 20 | Créer du contenu (approbation requise pour publier) |
| Author | 30 | Créer/modifier/publier son propre contenu |
| Editor | 40 | Gérer tout le contenu |
| Admin | 50 | Accès complet, y compris les paramètres |
Chaque rôle hérite des permissions de tous les niveaux inférieurs. Le premier utilisateur est toujours créé en tant qu’Admin.
Abonnés et contenu en brouillon
Les abonnés détiennent la permission content:read afin que le contenu publié réservé aux membres puisse être servi aux lecteurs authentifiés. Ils ne peuvent pas voir les brouillons, les éléments planifiés, les éléments dans la corbeille, les révisions ni les URL d’aperçu — ceux-ci sont contrôlés par content:read_drafts, accordé à Contributor et au-dessus. Les endpoints list et get filtrent de manière transparente vers status=published pour les Subscribers ; les vues réservées aux éditeurs (/compare, /revisions, /trash, /preview-url) rejettent d’emblée les requêtes des Subscribers.
Inviter des utilisateurs
Les administrateurs peuvent inviter de nouveaux utilisateurs via le panneau d’administration :
-
Allez dans Settings > Users
-
Cliquez sur Invite User
-
Saisissez l’e-mail de l’utilisateur et sélectionnez un rôle
-
Cliquez sur Send Invite
-
Si l’e-mail est configuré, EmDash envoie l’invitation. Sinon, copiez le lien généré et envoyez-le vous-même à l’utilisateur.
-
Ils ouvrent le lien et créent le compte avec une passkey ou un fournisseur de connexion proposé sur la page d’invitation.
Les liens d’invitation sont à usage unique et expirent après 7 jours.
Gérer les passkeys
Les utilisateurs peuvent gérer leurs passkeys depuis les paramètres du compte :
- Add passkey — Enregistrer des passkeys supplémentaires pour la sauvegarde ou d’autres appareils
- Remove passkey — Supprimer les passkeys que vous n’utilisez plus
- Rename passkey — Donner des noms descriptifs aux passkeys
Chaque utilisateur peut avoir jusqu’à 10 passkeys enregistrées.
EmDash n’autorise pas un utilisateur à supprimer sa dernière passkey. Ajoutez un remplacement avant de supprimer l’ancienne.
Autoriser un groupe à se connecter sans invitations
Pour autoriser un groupe à se connecter sans inviter chaque utilisateur, configurez un fournisseur de connexion avec une liste d’autorisation. Le fournisseur Atmosphere accepte allowedHandles et allowedDIDs (voir Connexion Atmosphere) ; l’adaptateur Cloudflare Access provisionne les utilisateurs depuis votre fournisseur d’identité via autoProvision et roleMapping. Les fournisseurs documentés GitHub, Google et Atmosphere peuvent aussi créer le compte administrateur initial.
Sessions
Les callbacks passkey, magic link, invitation et fournisseur de connexion stockent l’ID utilisateur EmDash dans le magasin de sessions d’Astro. Le navigateur reçoit l’identifiant opaque astro-session d’Astro ; les enregistrements utilisateur et d’identifiants restent dans la base de données EmDash.
Cloudflare Access écrit également l’utilisateur EmDash résolu dans la session Astro. Cela permet aux pages publiques d’identifier un utilisateur connecté lorsqu’elles lisent Astro.locals.user. La session ne remplace pas l’authentification Access sur les routes /_emdash protégées : EmDash valide à nouveau le JSON Web Token (JWT) Access sur ces requêtes.
Limites de débit d’authentification
EmDash limite les endpoints qui démarrent des flux de connexion ou d’inscription non authentifiés. Les limites sont séparées pour chaque endpoint et chaque IP client de confiance :
| Endpoint | Limit |
|---|---|
POST /_emdash/api/auth/passkey/options | 10 requêtes par minute |
POST /_emdash/api/auth/magic-link/send | 3 requêtes par 5 minutes |
POST /_emdash/api/auth/signup/request | 3 requêtes par 5 minutes |
Sur Cloudflare, EmDash lit l’IP client depuis les métadonnées de requête Cloudflare. Un site auto-hébergé derrière un proxy inverse doit configurer trustedProxyHeaders avant qu’EmDash puisse utiliser l’en-tête IP client du proxy. Lorsqu’aucune IP de confiance n’est disponible, ces contrôles par IP sont ignorés car il n’y a pas de clé sûre à compter.
Les passkeys stockent des identifiants à clé publique ; la clé privée reste avec l’authentificateur de l’utilisateur. Les jetons magic link sont stockés sous forme de hachages SHA-256 et supprimés après utilisation.
Dépannage
”No passkeys registered”
Si vous voyez cette erreur à la connexion, votre passkey a peut-être été supprimée de votre gestionnaire de mots de passe. Demandez à un administrateur d’envoyer un magic link de récupération ; le site doit avoir l’e-mail configuré.
”Passkey authentication failed”
Cela signifie généralement que la passkey a été créée pour un domaine différent. Les passkeys sont liées au domaine — une passkey pour localhost:4321 ne fonctionnera pas sur example.com. Enregistrez une nouvelle passkey pour chaque domaine.
Toutes les passkeys perdues
Si vous avez perdu l’accès à toutes vos passkeys enregistrées :
- Demandez à un autre administrateur d’envoyer un magic link de récupération. Le site doit avoir l’e-mail configuré.
- Ouvrez le lien dans les 15 minutes et sélectionnez Continue pour vous connecter.
- Enregistrez une nouvelle passkey dans les paramètres du compte.
Si vous êtes le seul administrateur et que l’e-mail n’est pas configuré, vous devrez réinitialiser l’authentification du site via la base de données.
Cloudflare Access
Lors d’un déploiement sur Cloudflare, vous pouvez utiliser Cloudflare Access à la place des méthodes de connexion intégrées. Access authentifie l’utilisateur à la périphérie avec votre fournisseur d’identité. EmDash valide le JWT Access signé, charge l’identité et les groupes de la personne, et mappe cette identité à un utilisateur EmDash local.
Quand utiliser Cloudflare Access
- Single Sign-On — Les utilisateurs s’authentifient avec l’IdP de votre entreprise
- Contrôle d’accès centralisé — Gérez qui peut accéder à l’admin dans le tableau de bord Cloudflare
- Pas de gestion de passkeys — Pas besoin d’enregistrer ni de gérer des passkeys
- Rôles basés sur les groupes — Mappez automatiquement les groupes IdP aux rôles EmDash
Configurer Access
- Créez une application et une politique Cloudflare Access pour le chemin
/_emdash/*de votre site. Protéger uniquement/_emdash/admin/*laisse l’API REST sans le JWT qu’EmDash attend. - Copiez le Application Audience (AUD) Tag de l’application.
- Stockez le tag dans la variable d’environnement d’exécution
CF_ACCESS_AUDIENCE. Suivez le guide des secrets EmDash pour les valeurs locales et déployées. - Configurez EmDash pour lire cette valeur à l’exécution :
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",
}),
}),
],
});
L’audience de l’application identifie quelle application Access a émis le JWT. EmDash la vérifie avec l’émetteur et la signature ; un jeton pour une autre application Access est rejeté.
Options de configuration
| Option | Type | Default | Description |
|---|---|---|---|
teamDomain | string | required | Votre domaine d’équipe Access (ex. : myteam.cloudflareaccess.com) |
audience | string | — | Application Audience (AUD) Tag fourni directement. Préférez audienceEnvVar sur Workers. |
autoProvision | boolean | true | Créer des utilisateurs EmDash à la première connexion Access |
defaultRole | number | 30 | Rôle pour les utilisateurs ne correspondant à aucun groupe (30 = Author) |
syncRoles | boolean | false | Mettre à jour le rôle à chaque connexion selon les groupes IdP |
roleMapping | object | — | Mapper les noms de groupes IdP aux niveaux de rôle |
audienceEnvVar | string | "CF_ACCESS_AUDIENCE" | Variable d’environnement contenant le tag d’audience. Utilisée lorsque audience est omis. |
Fournissez soit audience, soit une valeur d’environnement sous audienceEnvVar.
Mapping des rôles
Mappez vos groupes IdP aux rôles 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
}),
});
Le premier groupe correspondant gagne si un utilisateur appartient à plusieurs groupes. Le premier utilisateur à accéder au site devient toujours Admin, indépendamment des groupes.
Comportement de synchronisation des rôles
Par défaut (syncRoles: false), le rôle d’un utilisateur est défini à la première connexion et ne change plus ensuite. Cela permet aux administrateurs d’ajuster manuellement les rôles dans EmDash.
Définissez syncRoles: true si vous voulez que les groupes IdP soient autoritaires — le rôle de l’utilisateur sera mis à jour à chaque connexion selon ses groupes actuels.
Flux de requête et de session
- L’utilisateur visite un chemin protégé par l’application Access.
- Cloudflare Access redirige l’utilisateur vers votre fournisseur d’identité lorsqu’aucune session Access n’existe.
- Après authentification, Access envoie un JWT signé à l’origine dans
Cf-Access-Jwt-Assertion. - EmDash valide la signature, l’émetteur et l’audience du jeton, puis lit l’identité et les groupes Access.
- EmDash trouve ou provisionne l’utilisateur local, applique le comportement de rôle configuré et enregistre l’utilisateur dans la session Astro.
- Les requêtes ultérieures vers les routes EmDash protégées répètent la validation Access. Les pages publiques peuvent utiliser la session EmDash pour identifier l’utilisateur sans la traiter comme preuve d’une nouvelle requête Access.
Fonctionnalités remplacées par Access
Lorsque Access est activé, ces fonctionnalités sont indisponibles :
- Page de connexion (
/_emdash/admin/login) - Enregistrement et gestion des passkeys
- Connexion GitHub, Google et Atmosphere
- Connexion par magic link
- Auto-inscription
- Invitations d’utilisateurs
Les politiques Access décident qui atteint EmDash. EmDash reste propriétaire des rôles locaux, de la propriété du contenu et de l’indicateur d’utilisateur désactivé. Avec syncRoles: false, les administrateurs peuvent modifier le rôle d’un utilisateur provisionné dans EmDash. Avec syncRoles: true, les groupes Access mappés remplacent ce rôle à chaque connexion.
Dépannage
”No Access JWT present”
La requête a atteint EmDash sans JWT Access. Cela signifie :
- Access n’est pas configuré pour protéger votre application
- La politique Access ne correspond pas aux routes d’administration
Vérifiez que l’application Access couvre le chemin complet /_emdash/* et que sa politique inclut l’utilisateur.
”JWT audience mismatch”
Le audience de votre configuration ne correspond pas au JWT. Vérifiez à nouveau l’Application Audience Tag dans les paramètres de votre application Access.
”User not authorized”
L’utilisateur s’est authentifié via Access mais autoProvision est false et il n’existe pas dans EmDash. Soit :
- Définissez
autoProvision: true, ou - Créez l’utilisateur manuellement avant qu’il se connecte