Autenticazione

In questa pagina

EmDash usa l’autenticazione con passkey come metodo di accesso principale. Le passkey resistono al phishing, non richiedono password e funzionano su tutti i dispositivi tramite il browser o il gestore di password.

Oltre alle passkey, puoi aggiungere provider di accesso collegabili. GitHub e Google sono inclusi con EmDash. Il provider Atmosphere installato separatamente aggiunge gli account AT Protocol, e la stessa interfaccia provider è aperta ad altri pacchetti. I provider documentati GitHub, Google e Atmosphere possono creare il primo account amministratore o accedere con un utente EmDash collegato.

Per le implementazioni Cloudflare, Cloudflare Access è una modalità di autenticazione separata ed esclusiva in produzione. Valida le credenziali Access sulle route EmDash protette invece di mostrare i metodi di accesso EmDash.

Scegliere una modalità di autenticazione

Le passkey usano WebAuthn, uno standard web che crea credenziali a chiave pubblica memorizzate sul dispositivo o sincronizzate tramite il gestore di password. Al login, il dispositivo dimostra il possesso della credenziale senza mai inviare una password sulla rete.

Le passkey sono l’impostazione predefinita. I provider GitHub, Google e Atmosphere sono metodi di accesso aggiuntivi: ciascuno autentica l’utente, collega o crea un account EmDash e stabilisce la stessa sessione EmDash usata da un login con passkey.

L’autenticazione con passkey offre:

  • Nessuna password da ricordare o far trapelare
  • Resistente al phishing — le credenziali sono legate al dominio del sito
  • Sincronizzazione tra dispositivi — funziona con iCloud Keychain, Google Password Manager, 1Password, ecc.
  • Accesso rapido — un tocco con biometria o PIN

Cloudflare Access usa l’opzione auth invece di authProviders. In produzione diventa l’autorità per le route /_emdash protette. EmDash memorizza comunque un utente locale affinché ruoli, proprietà e controlli sugli utenti disabilitati continuino a funzionare.

Configurare il primo utente

La prima volta che accedi al pannello di amministrazione, la procedura guidata ti guida nella creazione dell’account amministratore.

  1. Vai a http://localhost:4321/_emdash/admin

  2. In Set up your site, inserisci il titolo del sito e un slogan opzionale. Un modello può anche offrire contenuti di esempio. Seleziona Continue.

  3. In Create your account, inserisci il tuo indirizzo email e un nome opzionale. Seleziona Continue.

  4. In Secure your account, crea una passkey o scegli uno dei provider di accesso configurati. Se scegli una passkey, il browser chiede dove salvarla:

    • Su macOS: Touch ID, password del dispositivo o chiave di sicurezza
    • Su Windows: Windows Hello o chiave di sicurezza
    • Su mobile: Face ID, impronta digitale o PIN
  5. Completa il flusso del browser o del provider. EmDash crea il primo utente come Admin e apre la dashboard.

Accedere con una passkey

Dopo la configurazione, tornare al pannello di amministrazione attiva l’autenticazione con passkey:

  1. Visita /_emdash/admin

  2. Se non hai effettuato l’accesso, vedrai la pagina di login

  3. Fai clic su Sign in per autenticarti

  4. Il browser richiede la passkey (biometria, PIN o chiave di sicurezza)

  5. Dopo la verifica, vieni reindirizzato alla dashboard di amministrazione

Se non puoi usare la passkey, un magic link offre un’alternativa. Il sito deve avere un provider email configurato prima che EmDash possa inviare il link — vedi Configurazione email.

  1. Nella pagina di login, fai clic su Sign in with email

  2. Inserisci il tuo indirizzo email

  3. Controlla la casella di posta per un link di accesso

  4. Fai clic sul link (valido per 15 minuti), poi seleziona Continue nella pagina di conferma

    Il link viene usato solo quando selezioni Continue, così gli scanner di sicurezza email che aprono i link in anticipo non lo esauriscono.

Configurare i provider di accesso

Oltre alle passkey, EmDash supporta provider di accesso collegabili che compaiono nella pagina di login e nella procedura guidata. GitHub e Google sono inclusi con EmDash. Atmosphere e i provider di terze parti sono pacchetti separati che si registrano tramite la stessa interfaccia.

I provider sono additivi: le passkey continuano a funzionare quando i provider sono abilitati. GitHub e Google collegano automaticamente un utente EmDash esistente solo quando il provider fornisce lo stesso indirizzo email verificato. Gli account Atmosphere sono collegati dal loro identificatore decentralizzato (DID), perché il flusso Atmosphere di EmDash non riceve un indirizzo email. Ogni provider incluso può creare il primo utente, quindi un’installazione nuova può saltare del tutto le passkey.

Aggiungere provider ad Astro

Passa i provider all’array authProviders dell’integrazione EmDash. L’esempio seguente abilita GitHub, Google e 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’ordine conta per la pagina di login: i provider vengono visualizzati nell’ordine in cui li elenchi, con i provider compatti solo-pulsante per primi e i provider che richiedono un modulo personalizzato (come Atmosphere, che chiede un handle) dopo.

GitHub

L’esempio seguente abilita il provider GitHub:

import { github } from "emdash/auth/providers/github";

emdash({ authProviders: [github()] });

Imposta le credenziali tramite variabili d’ambiente. EmDash controlla prima i nomi con prefisso e poi ricorre a quelli senza prefisso:

VariablePurpose
EMDASH_OAUTH_GITHUB_CLIENT_ID / GITHUB_CLIENT_IDID client dell’app OAuth
EMDASH_OAUTH_GITHUB_CLIENT_SECRET / GITHUB_CLIENT_SECRETSecret dell’app OAuth

Configura l’URL di callback della tua app OAuth GitHub come https://your-site.example.com/_emdash/api/auth/oauth/github/callback.

Google

L’esempio seguente abilita il provider Google:

import { google } from "emdash/auth/providers/google";

emdash({ authProviders: [google()] });

Imposta le credenziali tramite variabili d’ambiente. EmDash controlla prima i nomi con prefisso e poi ricorre a quelli senza prefisso:

VariablePurpose
EMDASH_OAUTH_GOOGLE_CLIENT_ID / GOOGLE_CLIENT_IDID client dell’app OAuth
EMDASH_OAUTH_GOOGLE_CLIENT_SECRET / GOOGLE_CLIENT_SECRETSecret dell’app OAuth

Configura l’URI di reindirizzamento del client OAuth Google come https://your-site.example.com/_emdash/api/auth/oauth/google/callback.

Atmosphere (AT Protocol)

Per i siti i cui collaboratori hanno già un account Atmosphere — l’identità di proprietà dell’utente dietro Bluesky e la rete AT Protocol più ampia — installa il provider Atmosphere:

pnpm add @emdash-cms/auth-atproto

L’esempio seguente abilita il provider Atmosphere con un elenco di handle consentiti:

import { atproto } from "@emdash-cms/auth-atproto";

emdash({
	authProviders: [
		atproto({
			allowedHandles: ["*.example.com"],
		}),
	],
});

Non è necessario alcun secret client né variabile d’ambiente. Consulta la guida all’accesso Atmosphere per elenchi allowlist di handle/DID, mappatura dei ruoli e la configurazione di sviluppo locale richiesta dal profilo OAuth AT Protocol.

Creare un provider

Un provider è un AuthProviderDescriptor: un id, un’etichetta leggibile e i componenti admin, gestori di route, prefissi di route pubbliche e collezioni di storage di cui ha bisogno il flusso di accesso. Esporta un SetupStep da adminEntry se il provider deve comparire durante la configurazione del primo utente. La forma è esportata da 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: {},
		},
	};
}

Il pacchetto Atmosphere (@emdash-cms/auth-atproto) è il riferimento reale più completo per un provider che necessita di un modulo di accesso personalizzato, gestori di route OAuth e storage persistente.

Ruoli utente

EmDash usa il controllo degli accessi basato sui ruoli con cinque livelli:

RoleLevelDescription
Subscriber10Leggere i contenuti pubblicati (nessun accesso alle bozze)
Contributor20Creare contenuti (serve approvazione per pubblicare)
Author30Creare/modificare/pubblicare i propri contenuti
Editor40Gestire tutti i contenuti
Admin50Accesso completo, comprese le impostazioni

Ogni ruolo eredita le autorizzazioni di tutti i livelli inferiori. Il primo utente viene sempre creato come Admin.

Abbonati e contenuti in bozza

Gli abbonati hanno l’autorizzazione content:read affinché i contenuti pubblicati solo per i membri possano essere serviti ai lettori autenticati. Non possono vedere bozze, elementi programmati, elementi nel cestino, revisioni né URL di anteprima — quelli sono controllati da content:read_drafts, concesso a Contributor e superiori. Gli endpoint list e get filtrano in modo trasparente a status=published per i Subscriber; le viste solo per editor (/compare, /revisions, /trash, /preview-url) rifiutano categoricamente le richieste dei Subscriber.

Invitare utenti

Gli amministratori possono invitare nuovi utenti dal pannello di amministrazione:

  1. Vai a Settings > Users

  2. Fai clic su Invite User

  3. Inserisci l’email dell’utente e seleziona un ruolo

  4. Fai clic su Send Invite

  5. Se l’email è configurata, EmDash invia l’invito. Altrimenti, copia il link generato e invialo tu all’utente.

  6. Aprono il link e creano l’account con una passkey o un provider di accesso offerto nella pagina di invito.

I link di invito sono monouso e scadono dopo 7 giorni.

Gestire le passkey

Gli utenti possono gestire le passkey dalle impostazioni dell’account:

  • Add passkey — Registrare passkey aggiuntive per backup o altri dispositivi
  • Remove passkey — Eliminare le passkey che non usi più
  • Rename passkey — Dare alle passkey nomi descrittivi

Ogni utente può avere fino a 10 passkey registrate.

EmDash non consente a un utente di rimuovere l’ultima passkey. Aggiungi una sostituzione prima di eliminare quella vecchia.

Consentire a un gruppo di accedere senza inviti

Per consentire a un gruppo di accedere senza invitare ogni utente, configura un provider di accesso con un’allowlist. Il provider Atmosphere accetta allowedHandles e allowedDIDs (vedi Accesso Atmosphere); l’adapter Cloudflare Access effettua il provisioning degli utenti dal tuo identity provider tramite autoProvision e roleMapping. I provider documentati GitHub, Google e Atmosphere possono anche creare l’account amministratore iniziale.

Sessioni

I callback di passkey, magic link, invito e provider di accesso memorizzano l’ID utente EmDash nello store di sessioni di Astro. Il browser riceve l’identificatore opaco astro-session di Astro; i record utente e delle credenziali restano nel database EmDash.

Cloudflare Access scrive anche l’utente EmDash risolto nella sessione Astro. Ciò consente alle pagine pubbliche di identificare un utente connesso quando leggono Astro.locals.user. La sessione non sostituisce l’autenticazione Access sulle route /_emdash protette: EmDash convalida di nuovo il JSON Web Token (JWT) Access su quelle richieste.

Limiti di frequenza dell’autenticazione

EmDash limita gli endpoint che avviano flussi di accesso o registrazione non autenticati. I limiti sono separati per ogni endpoint e IP client attendibile:

EndpointLimit
POST /_emdash/api/auth/passkey/options10 richieste al minuto
POST /_emdash/api/auth/magic-link/send3 richieste per 5 minuti
POST /_emdash/api/auth/signup/request3 richieste per 5 minuti

Su Cloudflare, EmDash legge l’IP client dai metadati della richiesta Cloudflare. Un sito self-hosted dietro un reverse proxy deve configurare trustedProxyHeaders prima che EmDash possa usare l’header IP client del proxy. Quando non è disponibile alcun IP attendibile, questi controlli per IP vengono saltati perché non c’è una chiave sicura da contare.

Le passkey memorizzano credenziali a chiave pubblica; la chiave privata resta con l’autenticatore dell’utente. I token magic link sono memorizzati come hash SHA-256 ed eliminati dopo l’uso.

Risoluzione dei problemi

”No passkeys registered”

Se vedi questo errore al login, la passkey potrebbe essere stata eliminata dal gestore di password. Chiedi a un amministratore di inviare un magic link di recupero; il sito deve avere l’email configurata.

”Passkey authentication failed”

Di solito significa che la passkey è stata creata per un dominio diverso. Le passkey sono legate al dominio — una passkey per localhost:4321 non funzionerà su example.com. Registra una nuova passkey per ogni dominio.

Tutte le passkey perse

Se hai perso l’accesso a tutte le passkey registrate:

  1. Chiedi a un altro amministratore di inviare un magic link di recupero. Il sito deve avere l’email configurata.
  2. Apri il link entro 15 minuti e seleziona Continue per accedere.
  3. Registra una nuova passkey nelle impostazioni dell’account.

Se sei l’unico amministratore e l’email non è configurata, dovrai reimpostare l’autenticazione del sito tramite il database.

Cloudflare Access

Quando esegui il deploy su Cloudflare, puoi usare Cloudflare Access al posto dei metodi di accesso integrati. Access autentica l’utente all’edge con il tuo identity provider. EmDash convalida il JWT Access firmato, carica l’identità e i gruppi della persona e mappa quell’identità a un utente EmDash locale.

Quando usare Cloudflare Access

  • Single Sign-On — Gli utenti si autenticano con l’IdP dell’azienda
  • Controllo accessi centralizzato — Gestisci chi può accedere all’admin nella dashboard Cloudflare
  • Nessuna gestione passkey — Non serve registrare né gestire passkey
  • Ruoli basati sui gruppi — Mappa automaticamente i gruppi IdP ai ruoli EmDash

Configurare Access

  1. Crea un’applicazione e una policy Cloudflare Access per il percorso /_emdash/* del sito. Proteggere solo /_emdash/admin/* lascia la REST API senza il JWT che EmDash si aspetta.
  2. Copia l’Application Audience (AUD) Tag dell’applicazione.
  3. Memorizza il tag nella variabile d’ambiente di runtime CF_ACCESS_AUDIENCE. Segui la guida ai secret EmDash per i valori locali e deployati.
  4. Configura EmDash per leggere quel valore a runtime:
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 dell’applicazione identifica quale applicazione Access ha emesso il JWT. EmDash lo verifica insieme all’emittente e alla firma; un token per un’altra applicazione Access viene rifiutato.

Opzioni di configurazione

OptionTypeDefaultDescription
teamDomainstringrequiredIl tuo dominio team Access (es. myteam.cloudflareaccess.com)
audiencestring—Application Audience (AUD) Tag fornito direttamente. Preferisci audienceEnvVar su Workers.
autoProvisionbooleantrueCreare utenti EmDash al primo accesso Access
defaultRolenumber30Ruolo per utenti che non corrispondono ad alcun gruppo (30 = Author)
syncRolesbooleanfalseAggiornare il ruolo a ogni login in base ai gruppi IdP
roleMappingobject—Mappare i nomi dei gruppi IdP ai livelli di ruolo
audienceEnvVarstring"CF_ACCESS_AUDIENCE"Variabile d’ambiente che contiene il tag audience. Usata quando audience è omesso.

Fornisci audience oppure un valore d’ambiente sotto audienceEnvVar.

Mappatura dei ruoli

Mappa i tuoi gruppi IdP ai ruoli 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
	}),
});

Il primo gruppo corrispondente vince se un utente appartiene a più gruppi. Il primo utente che accede al sito diventa sempre Admin, indipendentemente dai gruppi.

Comportamento di sincronizzazione dei ruoli

Per impostazione predefinita (syncRoles: false), il ruolo di un utente viene impostato al primo login e non cambia dopo. Ciò consente agli amministratori di regolare manualmente i ruoli in EmDash.

Imposta syncRoles: true se vuoi che i gruppi IdP siano autorevoli: il ruolo dell’utente verrà aggiornato a ogni login in base ai gruppi attuali.

Flusso di richiesta e sessione

  1. L’utente visita un percorso protetto dall’applicazione Access.
  2. Cloudflare Access reindirizza l’utente al tuo identity provider quando non esiste una sessione Access.
  3. Dopo l’autenticazione, Access invia un JWT firmato all’origine in Cf-Access-Jwt-Assertion.
  4. EmDash convalida la firma, l’emittente e l’audience del token, poi legge l’identità e i gruppi Access.
  5. EmDash trova o effettua il provisioning dell’utente locale, applica il comportamento dei ruoli configurato e registra l’utente nella sessione Astro.
  6. Le richieste successive alle route EmDash protette ripetono la convalida Access. Le pagine pubbliche possono usare la sessione EmDash per identificare l’utente senza trattarla come prova di una nuova richiesta Access.

Funzionalità sostituite da Access

Quando Access è abilitato, queste funzionalità non sono disponibili:

  • Pagina di login (/_emdash/admin/login)
  • Registrazione e gestione delle passkey
  • Accesso GitHub, Google e Atmosphere
  • Accesso con magic link
  • Auto-registrazione
  • Inviti utente

Le policy Access decidono chi raggiunge EmDash. EmDash resta proprietario dei ruoli locali, della proprietà dei contenuti e del flag utente disabilitato. Con syncRoles: false, gli amministratori possono cambiare il ruolo di un utente provisionato in EmDash. Con syncRoles: true, i gruppi Access mappati sostituiscono quel ruolo a ogni login.

Risoluzione dei problemi

”No Access JWT present”

La richiesta ha raggiunto EmDash senza un JWT Access. Significa:

  • Access non è configurato per proteggere l’applicazione
  • La policy Access non corrisponde alle route di amministrazione

Verifica che l’applicazione Access copra l’intero percorso /_emdash/* e che la policy includa l’utente.

”JWT audience mismatch”

L’audience nella configurazione non corrisponde al JWT. Ricontrolla l’Application Audience Tag nelle impostazioni dell’applicazione Access.

”User not authorized”

L’utente si è autenticato tramite Access ma autoProvision è false e non esiste in EmDash. Oppure:

  • Imposta autoProvision: true, oppure
  • Crea l’utente manualmente prima che effettui l’accesso