EmDash utilise l’authentification par passkey comme méthode de connexion principale. Les passkeys sont résistants 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 modulaires. 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 à d’autres paquets. Les fournisseurs documentés GitHub, Google et Atmosphere peuvent créer le premier compte admin ou connecter un utilisateur EmDash lié.
Pour les déploiements Cloudflare, Cloudflare Access est un mode d’authentification séparé 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, un standard web qui crée des identifiants à clé publique stockés sur votre appareil ou synchronisés via votre gestionnaire de mots de passe. Quand vous vous connectez, votre appareil prouve la possession de l’identifiant sans jamais envoyer de mot de passe sur le réseau.
Les passkeys sont la méthode par défaut. Les fournisseurs GitHub, Google et Atmosphere sont des méthodes de connexion supplémentaires : chacun authentifie l’utilisateur, lie ou crée un compte EmDash, et établit la même session EmDash utilisée par une connexion par passkey.
L’authentification par passkey fournit :
- Aucun mot de passe à retenir ou qui puisse 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 tapotement avec la biométrie ou le PIN
Cloudflare Access utilise l’option auth au lieu de authProviders. En production, il devient l’autorité pour les routes protégées /_emdash. EmDash stocke toujours un utilisateur local pour que les rôles, la propriété et les vérifications 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 admin.
-
Naviguez vers
http://localhost:4321/_emdash/admin -
Sur Set up your site, entrez le titre du site et le slogan optionnel. Un modèle peut aussi offrir du contenu exemple. Sélectionnez Continue.
-
Sur Create your account, entrez votre adresse email et nom optionnel. Sélectionnez Continue.
-
Sur Secure your account, créez un passkey ou choisissez l’un des fournisseurs de connexion configurés. Si vous choisissez un passkey, votre navigateur demande où le sauvegarder :
- 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
-
Complétez le flux du navigateur ou du fournisseur. EmDash crée le premier utilisateur en Admin et ouvre le tableau de bord.
Se connecter avec un 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 lien magique
Si vous ne pouvez pas utiliser votre passkey, un lien magique fournit une alternative. Le site doit avoir un fournisseur d’email configuré avant qu’EmDash puisse envoyer le lien.
-
Sur la page de connexion, cliquez sur Sign in with email
-
Entrez votre adresse email
-
Vérifiez votre boîte de réception pour un lien de connexion
-
Cliquez sur le lien pour vous authentifier (valide 15 minutes)
Configurer les fournisseurs de connexion
En plus des passkeys, EmDash supporte des fournisseurs de connexion modulaires qui apparaissent sur la page de connexion et dans l’assistant de configuration. GitHub et Google sont inclus avec EmDash. Les fournisseurs Atmosphere et tiers sont des paquets séparés qui s’enregistrent via la même interface.
Les fournisseurs sont additifs — les passkeys continuent de fonctionner quand les fournisseurs sont activés. GitHub et Google lient automatiquement un utilisateur EmDash existant uniquement quand le fournisseur fournit la même adresse email 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 email. Chaque fournisseur inclus peut créer le premier utilisateur, donc une installation neuve peut ignorer complètement 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 sont rendus dans l’ordre où vous les listez, avec les fournisseurs compacts à bouton seul en premier et les fournisseurs nécessitant 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 et se rabat sur ceux sans préfixe :
| Variable | Objectif |
|---|---|
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 et se rabat sur ceux sans préfixe :
| Variable | Objectif |
|---|---|
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 où 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. Voir le guide de connexion Atmosphere pour les listes de handles/DIDs autorisés, le mappage de rôles et la configuration de développement local que le profil OAuth AT Protocol exige.
Créer un fournisseur
Un fournisseur est un AuthProviderDescriptor : un id, un label lisible par l’humain, et les composants admin, 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", // exporte 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 nécessitant 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 :
| Rôle | Niveau | Description |
|---|---|---|
| Subscriber | 10 | Lire le contenu publié (pas d’accès aux brouillons) |
| Contributor | 20 | Créer du contenu (nécessite approbation pour publier) |
| Author | 30 | Créer/modifier/publier son propre contenu |
| Editor | 40 | Gérer tout le contenu |
| Admin | 50 | Accès complet incluant les paramètres |
Chaque rôle hérite des permissions de tous les niveaux inférieurs. Le premier utilisateur est toujours créé en Admin.
Subscribers et contenu en brouillon
Les Subscribers possèdent la permission content:read pour que le contenu publié réservé aux membres puisse être servi aux lecteurs authentifiés. Ils ne peuvent pas voir les brouillons, éléments programmés, éléments mis à la corbeille, révisions ou URLs de prévisualisation — ceux-ci sont protégés par content:read_drafts, accordé à Contributor et au-dessus. Les endpoints de liste et d’obtention filtrent transparemment sur status=published pour les Subscribers ; les vues réservées aux éditeurs (/compare, /revisions, /trash, /preview-url) rejettent directement les requêtes des Subscribers.
Inviter des utilisateurs
Les admins peuvent inviter de nouveaux utilisateurs via le panneau d’administration :
-
Allez dans Settings > Users
-
Cliquez sur Invite User
-
Entrez l’email de l’utilisateur et sélectionnez un rôle
-
Cliquez sur Send Invite
-
Si l’email est configuré, EmDash envoie l’invitation. Sinon, copiez le lien généré et envoyez-le vous-même à l’utilisateur.
-
L’utilisateur ouvre le lien et crée le compte avec un 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 :
- Ajouter un passkey — Enregistrer des passkeys supplémentaires comme sauvegarde ou pour d’autres appareils
- Supprimer un passkey — Supprimer les passkeys que vous n’utilisez plus
- Renommer un passkey — Donner des noms descriptifs aux passkeys
Chaque utilisateur peut avoir jusqu’à 10 passkeys enregistrés.
EmDash ne permet pas à un utilisateur de supprimer son dernier passkey. Ajoutez un remplacement avant de supprimer l’ancien.
Permettre à un groupe de se connecter sans invitations
Pour permettre à un groupe de 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 admin initial.
Sessions
Les callbacks de passkey, lien magique, 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 d’utilisateurs et d’identifiants restent dans la base de données EmDash.
Cloudflare Access écrit aussi l’utilisateur EmDash résolu dans la session Astro. Cela permet aux pages publiques d’identifier un utilisateur connecté quand elles lisent Astro.locals.user. La session ne remplace pas l’authentification Access sur les routes protégées /_emdash : 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 IP client de confiance :
| Endpoint | Limite |
|---|---|
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 de 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. Quand aucune IP de confiance n’est disponible, ces vérifications par IP sont ignorées car il n’y a pas de clé sûre pour compter.
Les passkeys stockent des identifiants à clé publique ; la clé privée reste avec l’authentificateur de l’utilisateur. Les tokens de lien magique sont stockés sous forme de hashes 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é de votre gestionnaire de mots de passe. Demandez à un admin d’envoyer un lien magique de récupération ; le site doit avoir l’email configuré.
”Passkey authentication failed”
Cela signifie généralement que le passkey a été créé pour un domaine différent. Les passkeys sont liés au domaine — un passkey pour localhost:4321 ne fonctionnera pas sur example.com. Enregistrez un nouveau passkey pour chaque domaine.
Tous les passkeys perdus
Si vous avez perdu l’accès à tous vos passkeys enregistrés :
- Demandez à un autre admin d’envoyer un lien magique de récupération. Le site doit avoir l’email configuré.
- Utilisez le lien dans les 15 minutes pour vous connecter.
- Enregistrez un nouveau passkey dans les paramètres du compte.
Si vous êtes le seul admin et que l’email n’est pas configuré, vous devrez réinitialiser l’authentification de votre site via la base de données.
Cloudflare Access
Lors du déploiement sur Cloudflare, vous pouvez utiliser Cloudflare Access à la place des méthodes de connexion intégrées. Access authentifie l’utilisateur en 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 ou 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 seulement/_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 runtime
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 token pour une autre application Access est rejeté.
Options de configuration
| Option | Type | Défaut | Description |
|---|---|---|---|
teamDomain | string | requis | 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 les utilisateurs EmDash lors de 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 basé sur 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 quand audience est omis. |
Fournissez soit audience soit une valeur d’environnement sous audienceEnvVar.
Mappage 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 pour les utilisateurs dans aucun groupe
}),
});
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 lors de sa première connexion et ne change pas ensuite. Cela permet aux admins 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 basé sur 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é quand aucune session Access n’existe.
- Après l’authentification, Access envoie un JWT signé à l’origine dans
Cf-Access-Jwt-Assertion. - EmDash valide la signature, l’émetteur et l’audience du token, 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 aux 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
Quand Access est activé, ces fonctionnalités ne sont pas disponibles :
- Page de connexion (
/_emdash/admin/login) - Enregistrement et gestion des passkeys
- Connexion GitHub, Google et Atmosphere
- Connexion par lien magique
- 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 du drapeau utilisateur désactivé. Avec syncRoles: false, les administrateurs peuvent changer 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”
L’audience dans votre configuration ne correspond pas au JWT. Vérifiez le 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. Options :
- Définissez
autoProvision: true, ou - Créez l’utilisateur manuellement avant qu’il se connecte