Autenticação

Nesta página

O EmDash utiliza autenticação com passkey como seu método principal de login. Passkeys são resistentes a phishing, não exigem senhas e funcionam entre dispositivos através do seu navegador ou gerenciador de senhas.

Além das passkeys, você pode adicionar provedores de login conectáveis. GitHub e Google estão incluídos com o EmDash. O provedor Atmosphere instalado separadamente adiciona contas AT Protocol, e a mesma interface de provedor está aberta a outros pacotes. Os provedores documentados GitHub, Google e Atmosphere podem criar a primeira conta de administrador ou fazer login com um usuário EmDash vinculado.

Para deployments no Cloudflare, Cloudflare Access é um modo de autenticação separado e exclusivo em produção. Ele valida credenciais do Access nas rotas protegidas do EmDash em vez de mostrar os métodos de login do EmDash.

Escolher um modo de autenticação

Passkeys usam WebAuthn, um padrão web que cria credenciais de chave pública armazenadas no seu dispositivo ou sincronizadas pelo seu gerenciador de senhas. Ao fazer login, seu dispositivo prova a posse da credencial sem nunca enviar uma senha pela rede.

Passkeys são o padrão. Os provedores GitHub, Google e Atmosphere são métodos de login adicionais: cada um autentica o usuário, vincula ou cria uma conta EmDash e estabelece a mesma sessão EmDash usada por um login com passkey.

A autenticação com passkey fornece:

  • Sem senhas para lembrar ou vazar
  • Resistente a phishing — credenciais sã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

O Cloudflare Access usa a opção auth em vez de authProviders. Em produção, ele se torna a autoridade para rotas protegidas /_emdash. O EmDash continua armazenando um usuário local para que papéis, propriedade e verificações de usuários desabilitados continuem funcionando.

Configurar o primeiro usuário

A primeira vez que você acessa o painel de administração, o Assistente de Configuração guia você na criação da sua conta de administrador.

  1. Navegue para http://localhost:4321/_emdash/admin

  2. Em Set up your site, digite o título do site e o slogan opcional. Um template também pode oferecer conteúdo de exemplo. Selecione Continue.

  3. Em Create your account, digite seu endereço de email e nome opcional. Selecione Continue.

  4. Em Secure your account, crie uma passkey ou escolha um dos provedores de login configurados. Se escolher uma passkey, seu navegador pergunta onde salvá-la:

    • 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
  5. Complete o fluxo do navegador ou provedor. O EmDash cria o primeiro usuário como Admin e abre o painel.

Fazer login com uma passkey

Após a configuração, retornar ao painel de administração aciona a autenticação com passkey:

  1. Visite /_emdash/admin

  2. Se não estiver logado, você verá a página de login

  3. Clique em Sign in para autenticar

  4. Seu navegador solicita sua passkey (biometria, PIN ou chave de segurança)

  5. Após a verificação, você é redirecionado para o painel de administração

Se você não puder usar sua passkey, um link mágico fornece uma alternativa. O site deve ter um provedor de email configurado antes que o EmDash possa enviar o link.

  1. Na página de login, clique em Sign in with email

  2. Digite seu endereço de email

  3. Verifique sua caixa de entrada para um link de login

  4. Clique no link para autenticar (válido por 15 minutos)

Configurar provedores de login

Além das passkeys, o EmDash suporta provedores de login conectáveis que aparecem na página de login e no assistente de configuração. GitHub e Google estão incluídos com o EmDash. Os provedores Atmosphere e de terceiros são pacotes separados que se registram pela mesma interface.

Os provedores são aditivos — passkeys continuam funcionando quando provedores estão habilitados. GitHub e Google vinculam automaticamente um usuário EmDash existente apenas quando o provedor fornece o mesmo endereço de email verificado. Contas Atmosphere são vinculadas pelo seu identificador descentralizado (DID), porque o fluxo Atmosphere do EmDash não recebe um endereço de email. Cada provedor incluído pode criar o primeiro usuário, então uma instalação nova pode pular passkeys completamente.

Adicionar provedores ao Astro

Passe os 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 são renderizados na ordem em que você os lista, com provedores compactos de apenas botão primeiro e provedores que precisam de um formulário personalizado (como Atmosphere, que pede um handle) 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. O EmDash verifica primeiro os nomes com prefixo e recorre aos sem prefixo:

VariávelPropósito
EMDASH_OAUTH_GITHUB_CLIENT_ID / GITHUB_CLIENT_IDID do cliente da app OAuth
EMDASH_OAUTH_GITHUB_CLIENT_SECRET / GITHUB_CLIENT_SECRETSegredo da app OAuth

Configure a URL de callback da sua app OAuth do GitHub como https://your-site.example.com/_emdash/api/auth/oauth/github/callback.

Google

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. O EmDash verifica primeiro os nomes com prefixo e recorre aos sem prefixo:

VariávelPropósito
EMDASH_OAUTH_GOOGLE_CLIENT_ID / GOOGLE_CLIENT_IDID do cliente da app OAuth
EMDASH_OAUTH_GOOGLE_CLIENT_SECRET / GOOGLE_CLIENT_SECRETSegredo da 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 os colaboradores já têm uma conta Atmosphere — a identidade pertencente ao 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 handles 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 handles/DIDs permitidos, mapeamento de papéis e a configuração de desenvolvimento local que o perfil OAuth do AT Protocol requer.

Criar um provedor

Um provedor é um AuthProviderDescriptor: um id, um rótulo legível e os componentes admin, manipuladores de rota, prefixos de rota pública e coleções de armazenamento que seu fluxo de login precisa. Exporte um SetupStep de adminEntry se o provedor deve aparecer durante a configuração do primeiro usuário. 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", // exporta 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 real mais completa para um provedor que precisa de um formulário de login personalizado, manipuladores de rota OAuth e armazenamento persistente.

Papéis de usuário

O EmDash usa controle de acesso baseado em papéis com cinco níveis:

PapelNívelDescrição
Subscriber10Ler conteúdo publicado (sem acesso a rascunhos)
Contributor20Criar conteúdo (precisa aprovação para publicar)
Author30Criar/editar/publicar conteúdo próprio
Editor40Gerenciar todo o conteúdo
Admin50Acesso completo incluindo configurações

Cada papel herda permissões de todos os níveis inferiores. O primeiro usuário é sempre criado como Admin.

Subscribers e conteúdo em rascunho

Subscribers possuem a permissão content:read para que conteúdo publicado exclusivo para membros possa ser servido a leitores autenticados. Eles não podem ver rascunhos, itens agendados, itens na lixeira, revisões ou URLs de preview — estes são controlados por content:read_drafts, concedido a Contributor e acima. Os endpoints de lista e obtenção filtram transparentemente para status=published para Subscribers; visualizações exclusivas de editores (/compare, /revisions, /trash, /preview-url) rejeitam diretamente solicitações de Subscribers.

Convidar usuários

Admins podem convidar novos usuários pelo painel de administração:

  1. Vá para Settings > Users

  2. Clique em Invite User

  3. Digite o email do usuário e selecione um papel

  4. Clique em Send Invite

  5. Se o email estiver configurado, o EmDash envia o convite. Caso contrário, copie o link gerado e envie você mesmo ao usuário.

  6. O usuário abre o link e cria a conta com uma passkey ou um provedor de login oferecido na página de convite.

Links de convite são de uso único e expiram após 7 dias.

Gerenciar passkeys

Usuários podem gerenciar suas passkeys nas configurações da conta:

  • Adicionar passkey — Registrar passkeys adicionais como backup ou para 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.

O EmDash não permite que um usuário remova sua última passkey. Adicione uma substituta antes de excluir a antiga.

Permitir 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ão. 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. Os provedores documentados GitHub, Google e Atmosphere também podem criar a conta de administrador inicial.

Sessões

Callbacks de passkey, link mágico, convite e provedor de login armazenam o ID do usuário EmDash no armazenamento de sessão do Astro. O navegador recebe o identificador opaco astro-session do Astro; registros de usuário e credenciais permanecem no banco de dados do EmDash.

O Cloudflare Access também escreve o usuário EmDash resolvido na sessão do Astro. Isso permite que páginas públicas identifiquem um usuário logado quando leem Astro.locals.user. A sessão não substitui a autenticação do Access nas rotas protegidas /_emdash: o EmDash valida o JSON Web Token (JWT) do Access novamente nessas solicitações.

Limites de taxa de autenticação

O EmDash limita os endpoints que iniciam fluxos de login ou cadastro não autenticados. Os limites são separados para cada endpoint e IP de cliente confiável:

EndpointLimite
POST /_emdash/api/auth/passkey/options10 solicitações por minuto
POST /_emdash/api/auth/magic-link/send3 solicitações por 5 minutos
POST /_emdash/api/auth/signup/request3 solicitações por 5 minutos

No Cloudflare, o EmDash lê o IP do cliente dos metadados de solicitação do Cloudflare. Um site auto-hospedado atrás de um proxy reverso deve configurar trustedProxyHeaders antes que o EmDash possa usar o cabeçalho de IP do cliente do proxy. Quando não há IP confiável disponível, essas verificações por IP são puladas porque não há chave segura para contar.

Passkeys armazenam credenciais de chave pública; a chave privada fica com o autenticador do usuário. Tokens de link mágico são armazenados como hashes SHA-256 e excluídos após o uso.

Solução de problemas

”No passkeys registered”

Se você vê este erro ao fazer login, sua passkey pode ter sido excluída do seu gerenciador de senhas. Peça a um admin para enviar um link mágico de recuperação; o site deve ter email configurado.

”Passkey authentication failed”

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.

Perdeu todas as passkeys

Se você perdeu acesso a todas as suas passkeys registradas:

  1. Peça a outro admin para enviar um link mágico de recuperação. O site deve ter email configurado.
  2. Use o link dentro de 15 minutos para fazer login.
  3. Registre uma nova passkey nas configurações da conta.

Se você é o único admin e o email não está configurado, precisará redefinir a autenticação do seu site pelo banco de dados.

Cloudflare Access

Ao fazer deploy no Cloudflare, você pode usar Cloudflare Access em vez dos métodos de login integrados. O Access autentica o usuário na borda com seu provedor de identidade. O EmDash valida o JWT do Access assinado, carrega a identidade e grupos da pessoa e mapeia essa identidade para um usuário EmDash local.

Quando usar Cloudflare Access

  • Single Sign-On — Usuários se autenticam com o IdP da sua empresa
  • Controle de acesso centralizado — Gerencie quem pode acessar o admin no painel do Cloudflare
  • Sem gerenciamento de passkeys — Não é necessário registrar ou gerenciar passkeys
  • Papéis baseados em grupos — Mapeie grupos do IdP para papéis do EmDash automaticamente

Configurar Access

  1. Crie uma aplicação e política do Cloudflare Access para o caminho /_emdash/* do seu site. Proteger apenas /_emdash/admin/* deixa a API REST sem o JWT que o EmDash espera.
  2. Copie o Application Audience (AUD) Tag da aplicação.
  3. Armazene a tag na variável de ambiente runtime CF_ACCESS_AUDIENCE. Siga o guia de segredos do EmDash para valores locais e implantados.
  4. Configure o EmDash para ler esse valor em tempo de execução:
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",
			}),
		}),
	],
});

O audience da aplicação identifica qual aplicação do Access emitiu o JWT. O EmDash o verifica junto com o emissor e a assinatura; um token para outra aplicação do Access é rejeitado.

Opções de configuração

OpçãoTipoPadrãoDescrição
teamDomainstringobrigatórioSeu domínio de equipe Access (ex., myteam.cloudflareaccess.com)
audiencestringApplication Audience (AUD) tag fornecida diretamente. Prefira audienceEnvVar no Workers.
autoProvisionbooleantrueCriar usuários EmDash no primeiro login com Access
defaultRolenumber30Papel para usuários que não correspondem a nenhum grupo (30 = Author)
syncRolesbooleanfalseAtualizar papel em cada login baseado em grupos do IdP
roleMappingobjectMapear nomes de grupos do IdP para níveis de papel
audienceEnvVarstring"CF_ACCESS_AUDIENCE"Variável de ambiente contendo a tag de audience. Usada quando audience é omitido.

Forneça audience ou um valor de ambiente sob audienceEnvVar.

Mapeamento de papéis

Mapeie seus grupos do IdP para papéis do 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 para usuários 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, independentemente dos grupos.

Comportamento de sincronização de papéis

Por padrão (syncRoles: false), o papel de um usuário é definido quando ele faz login pela primeira vez e não muda depois. Isso permite que admins ajustem papéis manualmente no EmDash.

Defina syncRoles: true se quiser que os grupos do IdP sejam autoritativos — o papel do usuário será atualizado em cada login baseado em seus grupos atuais.

Fluxo de solicitação e sessão

  1. O usuário visita um caminho protegido pela aplicação do Access.
  2. O Cloudflare Access redireciona o usuário para seu provedor de identidade quando não existe sessão do Access.
  3. Após a autenticação, o Access envia um JWT assinado para a origem em Cf-Access-Jwt-Assertion.
  4. O EmDash valida a assinatura, o emissor e o audience do token, então lê a identidade e grupos do Access.
  5. O EmDash encontra ou provisiona o usuário local, aplica o comportamento de papel configurado e registra o usuário na sessão do Astro.
  6. Solicitações posteriores às rotas protegidas do EmDash repetem a validação do Access. Páginas públicas podem usar a sessão do EmDash para identificar o usuário sem tratá-la como prova de uma nova solicitação do Access.

Recursos substituídos pelo Access

Quando o Access está habilitado, estes recursos não estão disponíveis:

  • Página de login (/_emdash/admin/login)
  • Registro e gerenciamento de passkeys
  • Login com GitHub, Google e Atmosphere
  • Login com link mágico
  • Autocadastro
  • Convites de usuário

Políticas do Access decidem quem alcança o EmDash. O EmDash ainda possui papéis locais, propriedade de conteúdo e o flag de usuário desabilitado. Com syncRoles: false, administradores podem mudar o papel de um usuário provisionado no EmDash. Com syncRoles: true, os grupos do Access mapeados substituem esse papel em cada login.

Solução de problemas

”No Access JWT present”

A solicitação alcançou o EmDash sem um JWT do Access. Isso significa:

  • O Access não está configurado para proteger sua aplicação
  • A política do Access não está correspondendo às rotas de administração

Verifique que a aplicação do Access cobre o caminho completo /_emdash/* e que sua política inclui o usuário.

”JWT audience mismatch”

O audience na sua configuração não corresponde ao JWT. Verifique o Application Audience Tag nas configurações da sua aplicação do Access.

”User not authorized”

O usuário se autenticou via Access mas autoProvision é false e ele não existe no EmDash. Opções:

  • Defina autoProvision: true, ou
  • Crie o usuário manualmente antes dele fazer login