EmDash usa autenticação passkey como seu método principal de login. Passkeys são resistentes a phishing, não requerem senhas e funcionam em todos os dispositivos através do seu navegador ou gerenciador de senhas.
Além das passkeys, você pode adicionar provedores de login plugáveis — GitHub, Google e Atmosphere (AT Protocol) vêm prontos para uso, e a mesma interface de provedor está aberta para pacotes de terceiros. Qualquer provedor configurado pode ser usado para criar a primeira conta de administrador, fazer login ou vincular a um usuário existente.
Para implantações Cloudflare, Cloudflare Access também está disponível como um método de autenticação exclusivo que assume todo o fluxo de login.
Como funciona
Passkeys usam WebAuthn, um padrão web que cria credenciais de chave pública armazenadas no seu dispositivo ou sincronizadas através do seu gerenciador de senhas. Quando você faz login, seu dispositivo prova a posse da credencial sem nunca enviar uma senha pela rede.
Benefícios da autenticação passkey:
- Sem senhas para lembrar ou vazar
- Resistente a phishing — as credenciais estão vinculadas ao domínio do seu site
- Sincronização entre dispositivos — funciona com iCloud Keychain, Google Password Manager, 1Password, etc.
- Login rápido — um toque com biometria ou PIN
Configuração do primeiro usuário
Na primeira vez que você acessa o painel de administração, o Assistente de Configuração o guia através da criação da sua conta de administrador.
-
Navegue até
http://localhost:4321/_emdash/admin -
Você será redirecionado para o Assistente de Configuração. Digite:
- Título do site — O nome do seu site
- Slogan — Uma descrição curta
- Email do administrador — Seu endereço de email
-
Clique em Criar site para registrar sua passkey
-
Seu navegador solicitará que você crie uma passkey:
- No macOS: Touch ID, senha do dispositivo ou chave de segurança
- No Windows: Windows Hello ou chave de segurança
- No celular: Face ID, impressão digital ou PIN
-
Uma vez que sua passkey é registrada, você está logado e redirecionado para o painel de administração.
Fazendo login
Após a configuração, retornar ao painel de administração aciona a autenticação passkey:
-
Visite
/_emdash/admin -
Se não estiver logado, você verá a página de login
-
Clique em Entrar para autenticar
-
Seu navegador solicita sua passkey (biometria, PIN ou chave de segurança)
-
Após a verificação, você é redirecionado para o painel de administração
Link mágico como alternativa
Se você não pode usar sua passkey (por exemplo, dispositivo perdido), links mágicos fornecem uma alternativa. Isso requer que o email seja configurado.
-
Na página de login, clique em Entrar com email
-
Digite seu endereço de email
-
Verifique sua caixa de entrada para um link de login
-
Clique no link para autenticar (válido por 15 minutos)
Provedores de login
Além das passkeys, EmDash suporta provedores de login plugáveis que aparecem na página de login e no assistente de configuração. Provedores GitHub, Google e Atmosphere vêm na caixa; pacotes de terceiros podem registrar os seus próprios usando a mesma interface.
Provedores são aditivos — passkeys continuam funcionando quando provedores são habilitados, e usuários podem vincular um provedor a uma conta existente somente com passkey. O primeiro usuário também pode ser criado através de qualquer provedor configurado, então uma instalação nova pode pular passkeys completamente se você preferir.
Configurando provedores
Passe provedores para o array authProviders na integração EmDash. O exemplo a seguir habilita 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()],
}),
],
});
A ordem importa para a página de login: provedores renderizam na ordem que você os lista, com provedores compactos somente com botão primeiro e provedores que precisam de um formulário personalizado (como Atmosphere, que pede um identificador) mostrados depois.
GitHub
O exemplo a seguir habilita o provedor GitHub:
import { github } from "emdash/auth/providers/github";
emdash({ authProviders: [github()] });
Defina credenciais via variáveis de ambiente. EmDash verifica os nomes prefixados primeiro e recorre aos não prefixados:
| Variável | Propósito |
|---|---|
EMDASH_OAUTH_GITHUB_CLIENT_ID / GITHUB_CLIENT_ID | ID do cliente do app OAuth |
EMDASH_OAUTH_GITHUB_CLIENT_SECRET / GITHUB_CLIENT_SECRET | Segredo do app OAuth |
Configure a URL de callback do seu app OAuth do GitHub como https://your-site.example.com/_emdash/api/auth/oauth/github/callback.
O exemplo a seguir habilita o provedor Google:
import { google } from "emdash/auth/providers/google";
emdash({ authProviders: [google()] });
Defina credenciais via variáveis de ambiente. EmDash verifica os nomes prefixados primeiro e recorre aos não prefixados:
| Variável | Propósito |
|---|---|
EMDASH_OAUTH_GOOGLE_CLIENT_ID / GOOGLE_CLIENT_ID | ID do cliente do app OAuth |
EMDASH_OAUTH_GOOGLE_CLIENT_SECRET / GOOGLE_CLIENT_SECRET | Segredo do app OAuth |
Configure o URI de redirecionamento do seu cliente OAuth do Google como https://your-site.example.com/_emdash/api/auth/oauth/google/callback.
Atmosphere (AT Protocol)
Para sites onde colaboradores já têm uma conta Atmosphere — a identidade de propriedade do usuário por trás do Bluesky e da rede AT Protocol mais ampla — instale o provedor Atmosphere:
pnpm add @emdash-cms/auth-atproto
O exemplo a seguir habilita o provedor Atmosphere com uma lista de identificadores permitidos:
import { atproto } from "@emdash-cms/auth-atproto";
emdash({
authProviders: [
atproto({
allowedHandles: ["*.example.com"],
}),
],
});
Nenhum segredo de cliente ou variável de ambiente é necessário. Veja o guia de login Atmosphere para listas de identificadores/DID permitidos, mapeamento de funções e a configuração de desenvolvimento local que o perfil OAuth do Protocolo AT requer.
Construindo seu próprio provedor
Um provedor é apenas um AuthProviderDescriptor — um id, um rótulo legível e qualquer combinação de componentes React do lado do admin, manipuladores de rota, prefixos de rota pública e coleções de armazenamento. A forma é exportada de 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: {},
},
};
}
O pacote Atmosphere (@emdash-cms/auth-atproto) é a referência do mundo real mais completa para um provedor que precisa de um formulário de login personalizado, manipuladores de rota OAuth e armazenamento persistente.
Funções de usuário
EmDash usa controle de acesso baseado em funções com cinco níveis:
| Função | Nível | Descrição |
|---|---|---|
| Subscriber | 10 | Ler conteúdo publicado (sem acesso a rascunhos) |
| Contributor | 20 | Criar conteúdo (precisa de aprovação para publicar) |
| Author | 30 | Criar/editar/publicar próprio conteúdo |
| Editor | 40 | Gerenciar todo o conteúdo |
| Admin | 50 | Acesso completo incluindo configurações |
Cada função herda permissões de todos os níveis inferiores. O primeiro usuário é sempre criado como Admin.
Assinantes e conteúdo rascunho
Assinantes têm a permissão content:read para que conteúdo publicado somente para membros possa ser servido a leitores autenticados. Eles não podem ver rascunhos, itens agendados, itens na lixeira, revisões ou URLs de pré-visualização — esses são protegidos por content:read_drafts, concedido a Contributor e acima. Os endpoints de lista e obtenção filtram transparentemente para status=published para Assinantes; visualizações exclusivas para editores (/compare, /revisions, /trash, /preview-url) rejeitam solicitações de Assinantes diretamente.
Convidando usuários
Administradores podem convidar novos usuários através do painel de administração:
-
Vá para Configurações > Usuários
-
Clique em Convidar usuário
-
Digite o email do usuário e selecione uma função
-
Clique em Enviar convite
-
O usuário recebe um email com um link de convite
-
Ele clica no link e registra sua passkey
Convites são válidos por 7 dias. Administradores podem reenviar ou revogar convites da página de Usuários.
Gerenciando passkeys
Usuários podem gerenciar suas passkeys a partir das configurações da conta:
- Adicionar passkey — Registrar passkeys adicionais para backup ou outros dispositivos
- Remover passkey — Excluir passkeys que você não usa mais
- Renomear passkey — Dar nomes descritivos às passkeys
Cada usuário pode ter até 10 passkeys registradas.
Permitindo que um grupo faça login sem convites
Para permitir que um grupo faça login sem convidar cada usuário, configure um provedor de login com uma lista de permissões. O provedor Atmosphere aceita allowedHandles e allowedDIDs (veja login Atmosphere); o adaptador Cloudflare Access provisiona usuários do seu provedor de identidade via autoProvision e roleMapping. Qualquer provedor configurado também pode criar a conta de administrador inicial.
Sessões
Sessões usam cookies seguros, HttpOnly, SameSite=Lax e duram 30 dias com expiração deslizante — a expiração se redefine na atividade.
Notas de segurança
- Passkeys são armazenadas como chaves públicas — a chave privada nunca sai do seu dispositivo
- Verificação de desafio previne ataques de replay
- Limitação de taxa protege contra força bruta (5 tentativas/minuto/IP)
- Sessões são HttpOnly, Secure, SameSite=Lax para segurança de cookies
- Tokens de link mágico são hash SHA-256 — tokens brutos nunca são armazenados
Solução de problemas
”Nenhuma passkey registrada”
Se você vê este erro no login, sua passkey pode ter sido excluída do seu gerenciador de senhas. Peça a um administrador para enviar um link mágico ou novo convite.
”Falha na autenticação passkey”
Isso geralmente significa que a passkey foi criada para um domínio diferente. Passkeys são vinculadas ao domínio — uma passkey para localhost:4321 não funcionará em example.com. Registre uma nova passkey para cada domínio.
”Sessão expirada”
Sessões duram 30 dias por padrão com expiração deslizante. Se você for desconectado inesperadamente, limpe seus cookies e faça login novamente.
Perdi todas as passkeys
Se você perdeu acesso a todas as suas passkeys registradas:
- Peça a outro administrador para enviar um link mágico (requer configuração de email)
- Use o link mágico para fazer login
- Registre uma nova passkey nas configurações da conta
Se você é o único administrador e o email não está configurado, você precisará redefinir a autenticação do seu site através do banco de dados.
Cloudflare Access
Ao implantar no Cloudflare, você pode usar Cloudflare Access como seu provedor de autenticação em vez de passkeys. Access lida com autenticação na borda usando seu provedor de identidade existente.
Por que usar Cloudflare Access
- Single Sign-On — Usuários autenticam com o IdP da sua empresa
- Controle de acesso centralizado — Gerencie quem pode acessar o admin no painel Cloudflare
- Sem gerenciamento de passkey — Não é necessário registrar ou gerenciar passkeys
- Funções baseadas em grupos — Mapeie grupos IdP para funções EmDash automaticamente
Configuração
- Crie uma aplicação Cloudflare Access para seu site EmDash
- Anote a Application Audience (AUD) Tag das configurações da aplicação
- Configure EmDash para usar Access:
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",
audience: "abc123def456...", // From Access app settings
}),
}),
],
});
Opções de configuração
| Opção | Tipo | Padrão | Descrição |
|---|---|---|---|
teamDomain | string | obrigatório | Seu domínio de equipe Access (ex.: myteam.cloudflareaccess.com) |
audience | string | obrigatório | Tag Application Audience (AUD) das configurações Access |
autoProvision | boolean | true | Criar usuários EmDash no primeiro login Access |
defaultRole | number | 30 | Função para usuários que não correspondem a nenhum grupo (30 = Author) |
syncRoles | boolean | false | Atualizar função em cada login com base em grupos IdP |
roleMapping | object | — | Mapear nomes de grupos IdP para níveis de função |
audienceEnvVar | string | "CF_ACCESS_AUDIENCE" | Nome da variável de ambiente para a tag de audiência (alternativa ao hardcoding) |
Mapeamento de funções
Mapeie seus grupos IdP para funções EmDash:
emdash({
auth: access({
teamDomain: "myteam.cloudflareaccess.com",
audience: "abc123...",
roleMapping: {
Admins: 50, // Admin
"Content Editors": 40, // Editor
Writers: 30, // Author
},
defaultRole: 20, // Contributor para usuários que não estão em nenhum grupo
}),
});
O primeiro grupo correspondente vence se um usuário pertence a múltiplos grupos. O primeiro usuário a acessar o site sempre se torna Admin, independente de grupos.
Comportamento de sincronização de funções
Por padrão (syncRoles: false), a função de um usuário é definida quando ele faz login pela primeira vez e não muda depois. Isso permite que administradores ajustem funções manualmente no EmDash.
Defina syncRoles: true se você quer que grupos IdP sejam autoritativos — a função do usuário será atualizada em cada login com base em seus grupos atuais.
Como funciona
- Usuário visita
/_emdash/admin - Cloudflare Access intercepta e redireciona para seu IdP
- Usuário autentica (SSO, MFA, etc.)
- Access define um JWT assinado na requisição
- EmDash valida o JWT e cria/autentica o usuário
Recursos desabilitados
Quando Access está habilitado, esses recursos não estão disponíveis:
- Página de login (
/_emdash/admin/login) - Registro e gerenciamento de passkeys
- Login OAuth
- Login por link mágico
- Auto-registro
- Convites de usuários
Gerenciamento de usuários é feito inteiramente através de suas políticas Cloudflare Access.
Solução de problemas
”Nenhum JWT Access presente”
A requisição alcançou EmDash sem um JWT Access. Isso significa:
- Access não está configurado para proteger sua aplicação
- A política Access não está correspondendo às rotas admin
Verifique se sua aplicação Access cobre /_emdash/admin/*.
”Incompatibilidade de audiência JWT”
A audience em sua configuração não corresponde ao JWT. Verifique novamente a Application Audience Tag nas configurações da sua aplicação Access.
”Usuário não autorizado”
O usuário autenticou via Access, mas autoProvision é false e ele não existe no EmDash. Ou:
- Defina
autoProvision: true, ou - Crie o usuário manualmente antes de ele fazer login