EmDash verwendet Passkey-Authentifizierung als primäre Anmeldemethode. Passkeys sind phishing-resistent, benötigen keine Passwörter und funktionieren geräteübergreifend über Ihren Browser oder Passwortmanager.
Über Passkeys hinaus können Sie steckbare Login-Provider hinzufügen. GitHub und Google sind in EmDash enthalten. Der separat installierte Atmosphere-Provider fügt AT-Protocol-Konten hinzu, und dieselbe Provider-Schnittstelle steht anderen Paketen offen. Die dokumentierten GitHub-, Google- und Atmosphere-Provider können das erste Admin-Konto erstellen oder einen verknüpften EmDash-Benutzer anmelden.
Bei Cloudflare-Deployments ist Cloudflare Access in der Produktion ein separater, exklusiver Authentifizierungsmodus. Es validiert Access-Anmeldedaten auf geschützten EmDash-Routen, statt die EmDash-Anmeldemethoden anzuzeigen.
Authentifizierungsmodus wählen
Passkeys nutzen WebAuthn, einen Webstandard, der Public-Key-Credentials erstellt, die auf Ihrem Gerät gespeichert oder über Ihren Passwortmanager synchronisiert werden. Beim Anmelden beweist Ihr Gerät den Besitz der Credential, ohne jemals ein Passwort über das Netzwerk zu senden.
Passkeys sind der Standard. GitHub-, Google- und Atmosphere-Provider sind zusätzliche Anmeldemethoden: Jeder authentifiziert den Benutzer, verknüpft oder erstellt ein EmDash-Konto und stellt dieselbe EmDash-Sitzung her, die auch eine Passkey-Anmeldung verwendet.
Passkey-Authentifizierung bietet:
- Keine Passwörter zum Merken oder Leaken
- Phishing-resistent — Credentials sind an die Domain Ihrer Site gebunden
- Geräteübergreifende Sync — funktioniert mit iCloud Keychain, Google Password Manager, 1Password usw.
- Schnelle Anmeldung — ein Tipp mit Biometrie oder PIN
Cloudflare Access verwendet die Option auth statt authProviders. In der Produktion wird es zur Autorität für geschützte /_emdash-Routen. EmDash speichert weiterhin einen lokalen Benutzer, damit Rollen, Eigentümerschaft und Prüfungen deaktivierter Benutzer weiter funktionieren.
Ersten Benutzer einrichten
Beim ersten Zugriff auf das Admin-Panel führt der Setup-Assistent Sie durch die Erstellung Ihres Admin-Kontos.
-
Navigieren Sie zu
http://localhost:4321/_emdash/admin -
Geben Sie unter Set up your site den Site-Titel und optional einen Tagline ein. Eine Vorlage kann auch Beispielinhalte anbieten. Wählen Sie Continue.
-
Geben Sie unter Create your account Ihre E-Mail-Adresse und optional einen Namen ein. Wählen Sie Continue.
-
Erstellen Sie unter Secure your account einen Passkey oder wählen Sie einen der konfigurierten Login-Provider. Wenn Sie einen Passkey wählen, fragt Ihr Browser, wo er gespeichert werden soll:
- Auf macOS: Touch ID, Gerätepasswort oder Sicherheitsschlüssel
- Auf Windows: Windows Hello oder Sicherheitsschlüssel
- Auf Mobile: Face ID, Fingerabdruck oder PIN
-
Schließen Sie den Browser- oder Provider-Flow ab. EmDash erstellt den ersten Benutzer als Admin und öffnet das Dashboard.
Mit einem Passkey anmelden
Nach dem Setup löst die Rückkehr zum Admin-Panel die Passkey-Authentifizierung aus:
-
Besuchen Sie
/_emdash/admin -
Wenn Sie nicht angemeldet sind, sehen Sie die Login-Seite
-
Klicken Sie auf Sign in, um sich zu authentifizieren
-
Ihr Browser fragt nach Ihrem Passkey (Biometrie, PIN oder Sicherheitsschlüssel)
-
Nach der Verifizierung werden Sie zum Admin-Dashboard weitergeleitet
Mit einem Magic Link anmelden
Wenn Sie Ihren Passkey nicht verwenden können, bietet ein Magic Link eine Alternative. Die Site muss einen E-Mail-Provider konfiguriert haben, bevor EmDash den Link senden kann — siehe E-Mail-Einrichtung.
-
Klicken Sie auf der Login-Seite auf Sign in with email
-
Geben Sie Ihre E-Mail-Adresse ein
-
Prüfen Sie Ihren Posteingang auf einen Login-Link
-
Klicken Sie auf den Link (15 Minuten gültig) und wählen Sie dann auf der Bestätigungsseite Continue
Der Link wird nur verwendet, wenn Sie Continue wählen, sodass E-Mail-Sicherheitsscanner, die Links im Voraus öffnen, ihn nicht verbrauchen.
Login-Provider konfigurieren
Zusätzlich zu Passkeys unterstützt EmDash steckbare Login-Provider, die auf der Login-Seite und im Setup-Assistenten erscheinen. GitHub und Google sind in EmDash enthalten. Atmosphere und Drittanbieter-Provider sind separate Pakete, die sich über dieselbe Schnittstelle registrieren.
Provider sind additiv — Passkeys funktionieren weiter, wenn Provider aktiviert sind. GitHub und Google verknüpfen einen bestehenden EmDash-Benutzer automatisch nur, wenn der Provider dieselbe verifizierte E-Mail-Adresse liefert. Atmosphere-Konten werden über ihren dezentralen Bezeichner (DID) verknüpft, weil EmDashs Atmosphere-Flow keine E-Mail-Adresse erhält. Jeder enthaltene Provider kann den ersten Benutzer erstellen, sodass eine frische Installation Passkeys vollständig überspringen kann.
Provider zu Astro hinzufügen
Übergeben Sie Provider an das Array authProviders der EmDash-Integration. Das folgende Beispiel aktiviert GitHub, Google und 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()],
}),
],
});
Die Reihenfolge zählt für die Login-Seite: Provider werden in der Reihenfolge gerendert, in der Sie sie auflisten, mit kompakten Button-only-Providern zuerst und Providern, die ein benutzerdefiniertes Formular brauchen (wie Atmosphere, das nach einem Handle fragt), danach.
GitHub
Das folgende Beispiel aktiviert den GitHub-Provider:
import { github } from "emdash/auth/providers/github";
emdash({ authProviders: [github()] });
Setzen Sie Credentials über Umgebungsvariablen. EmDash prüft zuerst die präfixierten Namen und fällt auf die unpräfixierten zurück:
| Variable | Purpose |
|---|---|
EMDASH_OAUTH_GITHUB_CLIENT_ID / GITHUB_CLIENT_ID | OAuth-App-Client-ID |
EMDASH_OAUTH_GITHUB_CLIENT_SECRET / GITHUB_CLIENT_SECRET | OAuth-App-Secret |
Konfigurieren Sie die Callback-URL Ihrer GitHub-OAuth-App als https://your-site.example.com/_emdash/api/auth/oauth/github/callback.
Das folgende Beispiel aktiviert den Google-Provider:
import { google } from "emdash/auth/providers/google";
emdash({ authProviders: [google()] });
Setzen Sie Credentials über Umgebungsvariablen. EmDash prüft zuerst die präfixierten Namen und fällt auf die unpräfixierten zurück:
| Variable | Purpose |
|---|---|
EMDASH_OAUTH_GOOGLE_CLIENT_ID / GOOGLE_CLIENT_ID | OAuth-App-Client-ID |
EMDASH_OAUTH_GOOGLE_CLIENT_SECRET / GOOGLE_CLIENT_SECRET | OAuth-App-Secret |
Konfigurieren Sie die Redirect-URI Ihres Google-OAuth-Clients als https://your-site.example.com/_emdash/api/auth/oauth/google/callback.
Atmosphere (AT Protocol)
Für Sites, deren Mitwirkende bereits ein Atmosphere-Konto haben — die nutzereigene Identität hinter Bluesky und dem weiteren AT-Protocol-Netzwerk — installieren Sie den Atmosphere-Provider:
pnpm add @emdash-cms/auth-atproto
Das folgende Beispiel aktiviert den Atmosphere-Provider mit einer Handle-Allowlist:
import { atproto } from "@emdash-cms/auth-atproto";
emdash({
authProviders: [
atproto({
allowedHandles: ["*.example.com"],
}),
],
});
Kein Client-Secret oder Umgebungsvariable ist nötig. Siehe den Atmosphere-Login-Leitfaden für Handle-/DID-Allowlists, Rollenzuordnung und die lokale Entwicklungs-Einrichtung, die das AT-Protocol-OAuth-Profil erfordert.
Einen Provider bauen
Ein Provider ist ein AuthProviderDescriptor: eine id, ein menschenlesbares Label und die Admin-Komponenten, Route-Handler, öffentlichen Route-Präfixe und Storage-Collections, die sein Login-Flow braucht. Exportieren Sie einen SetupStep aus adminEntry, wenn der Provider während der Ersteinrichtung des ersten Benutzers erscheinen soll. Die Form wird aus emdash exportiert:
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: {},
},
};
}
Das Atmosphere-Paket (@emdash-cms/auth-atproto) ist die vollständigste reale Referenz für einen Provider, der ein benutzerdefiniertes Login-Formular, OAuth-Route-Handler und persistente Speicherung braucht.
Benutzerrollen
EmDash verwendet rollenbasierte Zugriffskontrolle mit fünf Stufen:
| Role | Level | Description |
|---|---|---|
| Subscriber | 10 | Veröffentlichten Inhalt lesen (kein Entwurfzugriff) |
| Contributor | 20 | Inhalt erstellen (braucht Freigabe zum Veröffentlichen) |
| Author | 30 | Eigenen Inhalt erstellen/bearbeiten/veröffentlichen |
| Editor | 40 | Alle Inhalte verwalten |
| Admin | 50 | Voller Zugriff einschließlich Einstellungen |
Jede Rolle erbt Berechtigungen aller niedrigeren Stufen. Der erste Benutzer wird immer als Admin erstellt.
Abonnenten und Entwurfsinhalt
Abonnenten halten die Berechtigung content:read, damit nur-Mitglieder-veröffentlichter Inhalt an authentifizierte Leser ausgeliefert werden kann. Sie können keine Entwürfe, geplanten Einträge, Papierkorb-Einträge, Revisionen oder Vorschau-URLs sehen — diese sind an content:read_drafts gebunden, das Contributor und höher gewährt wird. Die Listen- und Get-Endpunkte filtern für Abonnenten transparent auf status=published; Editor-only-Ansichten (/compare, /revisions, /trash, /preview-url) lehnen Abonnenten-Anfragen direkt ab.
Benutzer einladen
Admins können neue Benutzer über das Admin-Panel einladen:
-
Gehen Sie zu Settings > Users
-
Klicken Sie auf Invite User
-
Geben Sie die E-Mail des Benutzers ein und wählen Sie eine Rolle
-
Klicken Sie auf Send Invite
-
Wenn E-Mail konfiguriert ist, sendet EmDash die Einladung. Andernfalls kopieren Sie den generierten Link und senden Sie ihn selbst an den Benutzer.
-
Sie öffnen den Link und erstellen das Konto mit einem Passkey oder einem auf der Einladungsseite angebotenen Login-Provider.
Einladungslinks sind einmalig und laufen nach 7 Tagen ab.
Passkeys verwalten
Benutzer können ihre Passkeys in den Kontoeinstellungen verwalten:
- Add passkey — Weitere Passkeys für Backup oder andere Geräte registrieren
- Remove passkey — Passkeys löschen, die Sie nicht mehr nutzen
- Rename passkey — Passkeys beschreibende Namen geben
Jeder Benutzer kann bis zu 10 Passkeys registrieren.
EmDash lässt einen Benutzer seinen letzten Passkey nicht entfernen. Fügen Sie einen Ersatz hinzu, bevor Sie den alten löschen.
Einer Gruppe das Anmelden ohne Einladungen erlauben
Um einer Gruppe das Anmelden ohne Einladung jedes Benutzers zu erlauben, konfigurieren Sie einen Login-Provider mit einer Allowlist. Der Atmosphere-Provider akzeptiert allowedHandles und allowedDIDs (siehe Atmosphere-Login); der Cloudflare-Access-Adapter provisioniert Benutzer aus Ihrem Identitätsprovider über autoProvision und roleMapping. Die dokumentierten GitHub-, Google- und Atmosphere-Provider können auch das initiale Admin-Konto erstellen.
Sitzungen
Passkey-, Magic-Link-, Einladungs- und Login-Provider-Callbacks speichern die EmDash-Benutzer-ID im Astro-Sitzungsspeicher. Der Browser erhält Astros opaken astro-session-Bezeichner; Benutzer- und Credential-Datensätze bleiben in der EmDash-Datenbank.
Cloudflare Access schreibt den aufgelösten EmDash-Benutzer ebenfalls in die Astro-Sitzung. So können öffentliche Seiten einen angemeldeten Benutzer erkennen, wenn sie Astro.locals.user lesen. Die Sitzung ersetzt nicht die Access-Authentifizierung auf geschützten /_emdash-Routen: EmDash validiert das Access-JSON-Web-Token (JWT) bei diesen Anfragen erneut.
Authentifizierungs-Ratenlimits
EmDash begrenzt die Endpunkte, die unauthentifizierte Login- oder Signup-Flows starten. Die Limits gelten separat für jeden Endpunkt und jede vertrauenswürdige Client-IP:
| Endpoint | Limit |
|---|---|
POST /_emdash/api/auth/passkey/options | 10 Anfragen pro Minute |
POST /_emdash/api/auth/magic-link/send | 3 Anfragen pro 5 Minuten |
POST /_emdash/api/auth/signup/request | 3 Anfragen pro 5 Minuten |
Auf Cloudflare liest EmDash die Client-IP aus Cloudflares Anfrage-Metadaten. Eine selbst gehostete Site hinter einem Reverse-Proxy muss trustedProxyHeaders konfigurieren, bevor EmDash den Client-IP-Header des Proxys verwenden kann. Wenn keine vertrauenswürdige IP verfügbar ist, werden diese Pro-IP-Prüfungen übersprungen, weil es keinen sicheren Schlüssel zum Zählen gibt.
Passkeys speichern Public-Key-Credentials; der private Schlüssel bleibt beim Authenticator des Benutzers. Magic-Link-Tokens werden als SHA-256-Hashes gespeichert und nach Gebrauch gelöscht.
Fehlerbehebung
”No passkeys registered”
Wenn Sie diesen Fehler beim Login sehen, wurde Ihr Passkey möglicherweise aus Ihrem Passwortmanager gelöscht. Bitten Sie einen Admin, einen Recovery-Magic-Link zu senden; die Site muss E-Mail konfiguriert haben.
”Passkey authentication failed”
Das bedeutet normalerweise, dass der Passkey für eine andere Domain erstellt wurde. Passkeys sind domaingebunden — ein Passkey für localhost:4321 funktioniert nicht auf example.com. Registrieren Sie für jede Domain einen neuen Passkey.
Alle Passkeys verloren
Wenn Sie den Zugriff auf alle registrierten Passkeys verloren haben:
- Bitten Sie einen anderen Admin, einen Recovery-Magic-Link zu senden. Die Site muss E-Mail konfiguriert haben.
- Öffnen Sie den Link innerhalb von 15 Minuten und wählen Sie Continue, um sich anzumelden.
- Registrieren Sie in den Kontoeinstellungen einen neuen Passkey.
Wenn Sie der einzige Admin sind und E-Mail nicht konfiguriert ist, müssen Sie die Authentifizierung Ihrer Site über die Datenbank zurücksetzen.
Cloudflare Access
Beim Deployment auf Cloudflare können Sie Cloudflare Access statt der eingebauten Anmeldemethoden verwenden. Access authentifiziert den Benutzer am Edge mit Ihrem Identitätsprovider. EmDash validiert das signierte Access-JWT, lädt Identität und Gruppen der Person und mappt diese Identität auf einen lokalen EmDash-Benutzer.
Wann Cloudflare Access nutzen
- Single Sign-On — Benutzer authentifizieren sich mit dem IdP Ihres Unternehmens
- Zentrale Zugriffskontrolle — Verwalten Sie im Cloudflare-Dashboard, wer auf die Admin zugreifen kann
- Keine Passkey-Verwaltung — Kein Registrieren oder Verwalten von Passkeys nötig
- Gruppenbasierte Rollen — IdP-Gruppen automatisch auf EmDash-Rollen mappen
Access einrichten
- Erstellen Sie eine Cloudflare-Access-Anwendung und -Richtlinie für den Pfad
/_emdash/*Ihrer Site. Nur/_emdash/admin/*zu schützen lässt die REST-API ohne das JWT, das EmDash erwartet. - Kopieren Sie den Application Audience (AUD) Tag der Anwendung.
- Speichern Sie den Tag in der Runtime-Umgebungsvariable
CF_ACCESS_AUDIENCE. Folgen Sie dem EmDash-Secrets-Leitfaden für lokale und deployte Werte. - Konfigurieren Sie EmDash, diesen Wert zur Laufzeit zu lesen:
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",
}),
}),
],
});
Die Application Audience identifiziert, welche Access-Anwendung das JWT ausgestellt hat. EmDash prüft sie zusammen mit Issuer und Signatur; ein Token für eine andere Access-Anwendung wird abgelehnt.
Konfigurationsoptionen
| Option | Type | Default | Description |
|---|---|---|---|
teamDomain | string | required | Ihre Access-Team-Domain (z. B. myteam.cloudflareaccess.com) |
audience | string | — | Application Audience (AUD) Tag direkt angegeben. Bevorzugen Sie audienceEnvVar auf Workers. |
autoProvision | boolean | true | EmDash-Benutzer beim ersten Access-Login erstellen |
defaultRole | number | 30 | Rolle für Benutzer, die keiner Gruppe entsprechen (30 = Author) |
syncRoles | boolean | false | Rolle bei jedem Login anhand der IdP-Gruppen aktualisieren |
roleMapping | object | — | IdP-Gruppennamen auf Rollenstufen mappen |
audienceEnvVar | string | "CF_ACCESS_AUDIENCE" | Umgebungsvariable mit dem Audience-Tag. Wird verwendet, wenn audience weggelassen wird. |
Geben Sie entweder audience oder einen Umgebungswert unter audienceEnvVar an.
Rollenzuordnung
Mappen Sie Ihre IdP-Gruppen auf EmDash-Rollen:
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
}),
});
Die erste passende Gruppe gewinnt, wenn ein Benutzer mehreren Gruppen angehört. Der erste Benutzer, der auf die Site zugreift, wird unabhängig von Gruppen immer Admin.
Verhalten der Rollensynchronisation
Standardmäßig (syncRoles: false) wird die Rolle eines Benutzers beim ersten Login gesetzt und ändert sich danach nicht. So können Admins Rollen in EmDash manuell anpassen.
Setzen Sie syncRoles: true, wenn IdP-Gruppen maßgeblich sein sollen — die Rolle des Benutzers wird bei jedem Login anhand seiner aktuellen Gruppen aktualisiert.
Anfrage- und Sitzungsfluss
- Der Benutzer besucht einen von der Access-Anwendung geschützten Pfad.
- Cloudflare Access leitet den Benutzer zu Ihrem Identitätsprovider um, wenn keine Access-Sitzung existiert.
- Nach der Authentifizierung sendet Access ein signiertes JWT an den Origin in
Cf-Access-Jwt-Assertion. - EmDash validiert Signatur, Issuer und Audience des Tokens und liest dann Access-Identität und Gruppen.
- EmDash findet oder provisioniert den lokalen Benutzer, wendet das konfigurierte Rollenverhalten an und speichert den Benutzer in der Astro-Sitzung.
- Spätere Anfragen an geschützte EmDash-Routen wiederholen die Access-Validierung. Öffentliche Seiten können die EmDash-Sitzung nutzen, um den Benutzer zu identifizieren, ohne sie als Beweis für eine neue Access-Anfrage zu behandeln.
Durch Access ersetzte Funktionen
Wenn Access aktiviert ist, sind diese Funktionen nicht verfügbar:
- Login-Seite (
/_emdash/admin/login) - Passkey-Registrierung und -Verwaltung
- GitHub-, Google- und Atmosphere-Login
- Magic-Link-Login
- Self-Signup
- Benutzereinladungen
Access-Richtlinien entscheiden, wer EmDash erreicht. EmDash besitzt weiterhin lokale Rollen, Inhalts-Eigentümerschaft und das Flag für deaktivierte Benutzer. Mit syncRoles: false können Administratoren die Rolle eines provisionierten Benutzers in EmDash ändern. Mit syncRoles: true ersetzen die gemappten Access-Gruppen diese Rolle bei jedem Login.
Fehlerbehebung
”No Access JWT present”
Die Anfrage erreichte EmDash ohne Access-JWT. Das bedeutet:
- Access ist nicht so konfiguriert, dass es Ihre Anwendung schützt
- Die Access-Richtlinie matcht die Admin-Routen nicht
Prüfen Sie, dass die Access-Anwendung den gesamten Pfad /_emdash/* abdeckt und dass ihre Richtlinie den Benutzer einschließt.
”JWT audience mismatch”
Die audience in Ihrer Konfiguration stimmt nicht mit dem JWT überein. Prüfen Sie den Application Audience Tag in den Einstellungen Ihrer Access-Anwendung.
”User not authorized”
Der Benutzer hat sich über Access authentifiziert, aber autoProvision ist false und er existiert nicht in EmDash. Entweder:
- Setzen Sie
autoProvision: true, oder - Erstellen Sie den Benutzer manuell, bevor er sich anmeldet