Autenticazione

In questa pagina

EmDash utilizza l’autenticazione con passkey come metodo di accesso principale. Le passkey sono resistenti 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 modulari. 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 admin o accedere con un utente EmDash collegato.

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

Scegliere una modalità di autenticazione

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

Le passkey sono il metodo predefinito. 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 accesso con passkey.

L’autenticazione con passkey fornisce:

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

Cloudflare Access utilizza l’opzione auth anziché authProviders. In produzione diventa l’autorità per le route protette /_emdash. 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 del tuo account admin.

  1. Naviga su http://localhost:4321/_emdash/admin

  2. Su Set up your site, inserisci il titolo del sito e il sottotitolo opzionale. Un template può anche offrire contenuti di esempio. Seleziona Continue.

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

  4. Su 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 sei connesso, vedrai la pagina di accesso

  3. Clicca su Sign in per autenticarti

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

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

Se non puoi usare la tua passkey, un link magico fornisce un’alternativa. Il sito deve avere un provider email configurato prima che EmDash possa inviare il link.

  1. Sulla pagina di accesso, clicca su Sign in with email

  2. Inserisci il tuo indirizzo email

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

  4. Clicca sul link per autenticarti (valido per 15 minuti)

Configurare i provider di accesso

Oltre alle passkey, EmDash supporta provider di accesso modulari che appaiono sulla pagina di accesso e nella procedura guidata. GitHub e Google sono inclusi con EmDash. I provider Atmosphere e 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 tramite il 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 completamente le passkey.

Aggiungere provider ad Astro

Passa i provider all’array authProviders nell’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 accesso: i provider vengono renderizzati nell’ordine in cui li elenchi, con i provider compatti solo-pulsante per primi e i provider che necessitano di 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 ricade su quelli senza:

VariabileScopo
EMDASH_OAUTH_GITHUB_CLIENT_ID / GITHUB_CLIENT_IDID client dell’app OAuth
EMDASH_OAUTH_GITHUB_CLIENT_SECRET / GITHUB_CLIENT_SECRETSegreto 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 ricade su quelli senza:

VariabileScopo
EMDASH_OAUTH_GOOGLE_CLIENT_ID / GOOGLE_CLIENT_IDID client dell’app OAuth
EMDASH_OAUTH_GOOGLE_CLIENT_SECRET / GOOGLE_CLIENT_SECRETSegreto dell’app OAuth

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

Atmosphere (AT Protocol)

Per siti dove i 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 una allowlist di handle:

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

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

Nessun segreto client o variabile d’ambiente necessaria. Vedi la guida all’accesso Atmosphere per allowlist di handle/DID, mappatura dei ruoli e la configurazione di sviluppo locale che il profilo OAuth AT Protocol richiede.

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 archiviazione di cui il suo flusso di accesso ha bisogno. Esporta un SetupStep da adminEntry se il provider deve apparire 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", // esporta 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 archiviazione persistente.

Ruoli utente

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

RuoloLivelloDescrizione
Subscriber10Leggere contenuti pubblicati (no accesso bozze)
Contributor20Creare contenuti (necessita approvazione per pubblicare)
Author30Creare/modificare/pubblicare i propri contenuti
Editor40Gestire tutti i contenuti
Admin50Accesso completo incluse le impostazioni

Ogni ruolo eredita i permessi da tutti i livelli inferiori. Il primo utente è sempre creato come Admin.

Subscriber e contenuti in bozza

I Subscriber possiedono il permesso content:read affinché i contenuti pubblicati riservati ai membri possano essere serviti ai lettori autenticati. Non possono vedere bozze, elementi programmati, elementi eliminati, revisioni o URL di anteprima — questi sono protetti da content:read_drafts, concesso a Contributor e superiori. Gli endpoint di lista e ottenimento filtrano trasparentemente su status=published per i Subscriber; le viste riservate agli editor (/compare, /revisions, /trash, /preview-url) rifiutano direttamente le richieste dei Subscriber.

Invitare utenti

Gli admin possono invitare nuovi utenti tramite il pannello di amministrazione:

  1. Vai su Settings > Users

  2. Clicca su Invite User

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

  4. Clicca su Send Invite

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

  6. L’utente apre il link e crea 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 loro passkey dalle impostazioni dell’account:

  • Aggiungere passkey — Registrare passkey aggiuntive come backup o per altri dispositivi
  • Rimuovere passkey — Eliminare le passkey che non usi più
  • Rinominare passkey — Dare nomi descrittivi alle passkey

Ogni utente può avere fino a 10 passkey registrate.

EmDash non permette a un utente di rimuovere la sua ultima passkey. Aggiungi un sostituto prima di eliminare quella vecchia.

Permettere a un gruppo di accedere senza inviti

Per permettere a un gruppo di accedere senza invitare ogni utente, configura un provider di accesso con una allowlist. Il provider Atmosphere accetta allowedHandles e allowedDIDs (vedi accesso Atmosphere); l’adattatore Cloudflare Access provisiona utenti dal tuo provider di identità tramite autoProvision e roleMapping. I provider documentati GitHub, Google e Atmosphere possono anche creare l’account admin iniziale.

Sessioni

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

Cloudflare Access scrive anche l’utente EmDash risolto nella sessione Astro. Questo permette alle pagine pubbliche di identificare un utente connesso quando leggono Astro.locals.user. La sessione non sostituisce l’autenticazione Access sulle route protette /_emdash: EmDash valida nuovamente 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:

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

Su Cloudflare, EmDash legge l’IP client dai metadati della richiesta di 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 un IP attendibile, questi controlli per IP vengono saltati perché non c’è una chiave sicura per contare.

Le passkey memorizzano credenziali a chiave pubblica; la chiave privata rimane con l’autenticatore dell’utente. I token dei link magici sono memorizzati come hash SHA-256 e cancellati dopo l’uso.

Risoluzione dei problemi

”No passkeys registered”

Se vedi questo errore all’accesso, la tua passkey potrebbe essere stata eliminata dal tuo gestore di password. Chiedi a un admin di inviare un link magico di recupero; il sito deve avere l’email configurata.

”Passkey authentication failed”

Questo 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.

Perse tutte le passkey

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

  1. Chiedi a un altro admin di inviare un link magico di recupero. Il sito deve avere l’email configurata.
  2. Usa il link entro 15 minuti per accedere.
  3. Registra una nuova passkey nelle impostazioni dell’account.

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

Cloudflare Access

Quando si effettua il deployment su Cloudflare, puoi usare Cloudflare Access al posto dei metodi di accesso integrati. Access autentica l’utente all’edge con il tuo provider di identità. EmDash valida 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 della tua azienda
  • Controllo degli accessi centralizzato — Gestisci chi può accedere all’admin nella dashboard Cloudflare
  • Nessuna gestione passkey — Non c’è bisogno di registrare o gestire passkey
  • Ruoli basati su 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 tuo sito. Proteggere solo /_emdash/admin/* lascia l’API REST senza il JWT che EmDash si aspetta.
  2. Copia l’Application Audience (AUD) Tag dell’applicazione.
  3. Memorizza il tag nella variabile d’ambiente runtime CF_ACCESS_AUDIENCE. Segui la guida ai segreti EmDash per i valori locali e distribuiti.
  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 la verifica insieme all’emittente e alla firma; un token per un’altra applicazione Access viene rifiutato.

Opzioni di configurazione

OpzioneTipoPredefinitoDescrizione
teamDomainstringobbligatorioIl tuo dominio team Access (es. myteam.cloudflareaccess.com)
audiencestringApplication Audience (AUD) tag fornito direttamente. Preferisci audienceEnvVar su Workers.
autoProvisionbooleantrueCreare utenti EmDash al primo accesso con Access
defaultRolenumber30Ruolo per utenti che non corrispondono a nessun gruppo (30 = Author)
syncRolesbooleanfalseAggiornare il ruolo ad ogni accesso basato sui gruppi IdP
roleMappingobjectMappare nomi di gruppi IdP a livelli di ruolo
audienceEnvVarstring"CF_ACCESS_AUDIENCE"Variabile d’ambiente contenente il tag audience. Usata quando audience è omesso.

Fornisci audience o 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 per utenti non in nessun gruppo
	}),
});

Il primo gruppo corrispondente vince se un utente appartiene a più gruppi. Il primo utente ad accedere 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 accesso e non cambia successivamente. Questo permette agli admin di regolare manualmente i ruoli in EmDash.

Imposta syncRoles: true se vuoi che i gruppi IdP siano autoritativi — il ruolo dell’utente verrà aggiornato ad ogni accesso basato sui suoi 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 provider di identità quando non esiste una sessione Access.
  3. Dopo l’autenticazione, Access invia un JWT firmato all’origine in Cf-Access-Jwt-Assertion.
  4. EmDash valida la firma, l’emittente e l’audience del token, poi legge l’identità e i gruppi Access.
  5. EmDash trova o provisiona l’utente locale, applica il comportamento di ruolo configurato e registra l’utente nella sessione Astro.
  6. Le richieste successive alle route protette EmDash ripetono la validazione 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 accesso (/_emdash/admin/login)
  • Registrazione e gestione delle passkey
  • Accesso con GitHub, Google e Atmosphere
  • Accesso con link magico
  • Auto-registrazione
  • Inviti utente

Le policy Access decidono chi raggiunge EmDash. EmDash possiede comunque i ruoli locali, la proprietà dei contenuti e il 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 ad ogni accesso.

Risoluzione dei problemi

”No Access JWT present”

La richiesta ha raggiunto EmDash senza un JWT Access. Questo significa:

  • Access non è configurato per proteggere la tua applicazione
  • La policy Access non corrisponde alle route di amministrazione

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

”JWT audience mismatch”

L’audience nella tua configurazione non corrisponde al JWT. Controlla l’Application Audience Tag nelle impostazioni della tua applicazione Access.

”User not authorized”

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

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