auth
Cadastro, entrada, OAuth, tokens e verificação de sessão.
O namespace de topo. Tudo aqui está disponível nos dois clients, mas o client de
navegador também guarda o que recebe de volta — um signIn bem-sucedido deixa
a sessão em disco e o token renovando em segundo plano, enquanto a mesma chamada
no servidor devolve os tokens e os esquece.
Onde um método precisa de sessão, um header Authorization que você já envia
tem prioridade — por chamada em options.headers, ou em todas as chamadas pela
opção headers do client, com qualquer capitalização, então o header minúsculo
que o forwardUserHeaders produz funciona direto. Sem ele, o client de
navegador lê o token do armazenamento. Nenhum dos dois adivinha: uma chamada sem
token disponível falha localmente com no_session e nunca sai do processo.
signUp
signUp(params) → Authenticated
Cria um usuário. O que volta depende de como o ambiente confirma contas, então ramifique pela resposta em vez de supor.
const { data, error } = await nulvless.auth.signUp({
email: '[email protected]',
password,
profile: { name: 'Ada Lovelace' },
});emailstringOptionalObrigatório a menos que phone seja informado.
phonePhoneOptional{ country_code, number } — não uma string formatada.
usernamestringOptional3 a 30 caracteres: letras, números, pontos, underscores. Não basta sozinho — o cadastro sempre precisa também de um e-mail ou telefone.
passwordstringRequiredVerificada contra as regras de tamanho, caracteres e vazamento do ambiente.
profileUserProfileOptionalNome, avatar e o resto dos dados da pessoa.
Devolve Authenticated. Leia o challenge primeiro — a conta não é utilizável
até a confirmação terminar, e com confirmação por código o registro do usuário
ainda nem existe. Veja Cadastro e verificação para a
ramificação completa.
Um único cadastro pode ser rejeitado por vários campos de uma vez, e nesse caso
error.message é um array. Trate isso de forma centralizada, não em cada
formulário.
signIn
signIn(params) → Authenticated
Entrada por senha. Identifique a pessoa pela credencial que o seu produto usa.
const { data, error } = await nulvless.auth.signIn({ email, password });
if (error) return showError();
if (data.challenge) return goToVerify(data.challenge);emailstringOptionalphonePhoneOptionalusernamestringOptionalpasswordstringRequiredoptionsAuthOptionsOptionalSobrescritas por chamada, incluindo o token de captcha quando o ambiente exige um para a entrada.
Dois desfechos, nesta ordem:
data.challenge— a pessoa tem um segundo fator, ou o ambiente exige um. Ninguém está autenticado ainda; leve o desafio até overifyChallenge.data.access_token— autenticado. O client de navegador já guardou a sessão e emitiusigned-in.
Uma senha errada responde 401 invalid_credentials. Não diferencie "usuário não
existe" de "senha errada" no seu texto — a plataforma deliberadamente não
diferencia.
signInWithOTP
signInWithOTP(params) → Challenge
Entrada sem senha: envia um código e devolve o desafio para coletá-lo.
const { data: challenge } = await nulvless.auth.signInWithOTP({
email: '[email protected]',
});emailstringOptionalphonePhoneOptionaloptionsAuthOptionsOptionalResponde 202 Accepted com um Challenge, não com uma sessão — a sessão só
aparece depois do verifyChallenge. O método precisa estar
habilitado no ambiente, ou a chamada é recusada.
Como ela envia mensagem, esta chamada tem limite de taxa.
lookup
lookup(params) → LookupResult
Pergunta o que um identificador consegue fazer, antes de pedir uma senha.
const { data } = await nulvless.auth.lookup({ email });
if (data.challenge) return goToVerify(data.challenge);emailstringOptionalphonePhoneOptionalusernamestringOptionalÉ com isso que se monta uma tela de entrada adaptativa: colete o e-mail,
pergunte à plataforma, e então renderize um campo de senha ou um campo de código
em vez de adivinhar. O data.lookup descreve o que casou.
O lookup pode devolver um challenge já iniciado quando o único método da
pessoa é OTP — um código foi enviado. Verifique isso antes de renderizar um
campo de senha, ou você vai enviar um segundo código quando ela submeter.
authorize
authorize(provider, options) → { url, provider }
Inicia uma entrada social.
await nulvless.auth.authorize('google', {
redirect_uri: `${window.location.origin}/callback`,
});providerOAuthProviderRequiredTambém precisa estar habilitado no ambiente.
googlegithubgitlabbitbucketfacebooklinked_inRepare no underscore.discordtwitchslackazureappleoptions.redirect_uristringOptionalOnde o fluxo aterrissa quando termina. Precisa estar na lista permitida do ambiente, ou a requisição é rejeitada antes de existir qualquer token.
No navegador ele redireciona por você — a URL devolvida é atribuída a
window.location e a promise nunca resolve de forma útil. No servidor nada é
redirecionado; use o data.url você mesmo:
const { data } = await nulvless.auth.authorize('google', {
redirect_uri: 'https://app.example.com/callback',
});
return Response.redirect(data.url);Prefira renderizar os botões de provedor a partir do
getMethods() em vez de cravá-los no código, para habilitar um
no console não exigir um redeploy.
connect
connect(provider, options) → { url, provider }
O mesmo redirecionamento OAuth, para quem já está autenticado. A identidade do provedor é ligada à conta atual em vez de iniciar uma entrada nova.
await nulvless.auth.connect('github', {
redirect_uri: `${window.location.origin}/settings/connections`,
});Exige sessão. É a chamada por trás de uma tela de "contas conectadas" — e o motivo de alguém acabar com senha, identidade do Google e identidade do GitHub resolvendo todas para um id só.
signInWithIdToken
signInWithIdToken(provider, idToken) → Authenticated
Entra com um ID token que você já obteve nativamente — um app mobile usando o SDK do Google Sign-In, por exemplo, onde a dança de redirecionamento já aconteceu fora do navegador.
const { data } = await nulvless.auth.signInWithIdToken('google', googleIdToken);Guarda a sessão automaticamente quando uma volta.
exchangeCodeForToken
exchangeCodeForToken(code) → Authenticated
Troca um authorization code de OAuth por uma sessão
(grant_type=authorization_code).
const code = new URLSearchParams(location.search).get('code');
if (code) await nulvless.auth.exchangeCodeForToken(code);codestringRequiredVindo do parâmetro de query code na sua URL de callback.
Você só precisa disso quando trata o callback você mesmo. O fluxo de navegador
iniciado pelo authorize é trocado para você.
verifyChallenge
verifyChallenge({ token, code }) → Authenticated
Envia o código de qualquer desafio — entrada por OTP, MFA depois da senha, ou confirmação de cadastro. Uma chamada encerra os três.
const { data } = await nulvless.auth.verifyChallenge({
token: challenge.token,
code,
});Apelido para o auth.challenges.verify, que é
também onde o limite de tentativas e o resto do ciclo de vida do desafio estão
descritos. A sessão é guardada automaticamente em caso de sucesso.
activate
activate(token) → null
Confirma uma conta a partir do link enviado por e-mail durante o cadastro.
const token = new URLSearchParams(location.search).get('token');
await nulvless.auth.activate(token);tokenstringRequiredVindo do parâmetro de query token na sua página de confirmação.
Não devolve nada — nenhuma sessão. Confirmar por link prova o endereço; não autentica a pessoa. Mande ela para a tela de entrada depois.
recover
recover({ email }) → null
Envia um e-mail de recuperação de senha.
await nulvless.auth.recover(
{ email },
{ redirect_uri: 'https://app.example.com/reset' },
);emailstringRequiredoptions.redirect_uristringOptionalOnde o link do e-mail aterrissa.
Resolve do mesmo jeito existindo o endereço ou não. Isso é deliberado — a resposta não pode dizer a um atacante quais endereços estão cadastrados — então a sua interface deve dizer "se esse endereço estiver cadastrado, enviamos um link" em vez de confirmar qualquer coisa.
resetPassword
resetPassword({ token, password }) → null
Completa a recuperação iniciada acima.
await nulvless.auth.resetPassword({ token, password: newPassword });tokenstringRequiredVindo do link de recuperação.
passwordstringRequiredVerificada contra as mesmas regras do cadastro.
Para quem está autenticado e simplesmente quer uma senha nova, use o
auth.security.changePassword — ele exige a senha
atual, o que este caminho não consegue.
getMethods
getMethods() → AuthMethods
Tudo com que o usuário atual consegue se autenticar, neste ambiente.
const { data } = await nulvless.auth.getMethods();
// data.sign_in · data.mfas · data.oauthExige sessão. Devolve três listas:
sign_inAuthMethod[]OptionalSenha, OTP e qualquer outra coisa habilitada para entrada.
mfasAuthMethod[]OptionalSegundos fatores, cada um com um status de configured ou not_configured.
Repare que o campo é mfas, no plural.
oauthAuthMethod[]OptionalProvedores sociais, incluindo os que esta pessoa não conectou.
Duas telas se constroem a partir disso: os botões de provedor na entrada, e a página de configurações de segurança listando o que está configurado e o que ainda está disponível.
getSession
getSession() → Session
A sessão atual — dispositivo, localização, os métodos usados para chegar nela, e se o sudo está ativo.
const { data: session, error } = await nulvless.auth.getSession();Exige sessão, e falha localmente com no_session quando não há nenhuma, então
serve também como "tem alguém autenticado?" sem ida à rede quando o
armazenamento está vazio.
getAccessToken
getAccessToken() → string | null
O access token atual, renovado antes se estiver expirado ou perto disso.
Este é o único método que não devolve um NulvlessResult — ele resolve para
a string do token, ou null quando não há sessão. Não há error para checar.
Chame a cada requisição em vez de guardar o resultado. Segurar a string anula a renovação, e um token que era válido quando você o guardou pode não ser quando você o enviar:
const token = await nulvless.auth.getAccessToken();
await fetch('/api/projects', {
headers: token ? { Authorization: `Bearer ${token}` } : {},
});refreshToken
refreshToken({ refresh_token }) → Authenticated
Troca um refresh token por uma sessão nova, e atualiza o armazenamento.
await nulvless.auth.refreshToken({ refresh_token: stored.refresh_token });O client de navegador faz isso por você — veja SessionManager. Chame diretamente quando você mesmo segura um refresh token, tipicamente num servidor que persistiu um.
verify
verify(grant?, options) → Verified
Responde duas perguntas numa chamada: este token ainda é válido, e quem o porta tem a permissão que você nomeou.
resourcestringOptionalSobre qual recurso é a pergunta. Omita para verificar só o token.
scopesstring[]OptionalQuem porta precisa ter todos.
rolesstring[]OptionalCasado contra a key do papel. Qualquer um basta. Ignorado quando nenhum
resource é informado.
Devolve Verified — o id do usuário, e uma sessão carregando os scopes
resolvidos para aquele recurso, o amr de como a pessoa se autenticou, e se o
sudo está ativo.
const { data, error } = await nulvless.auth.verify(
{ resource: 'acme', scopes: ['members:write'] },
{ headers: { Authorization: `Bearer ${token}` } },
);
if (error?.status_code === 401) return signInAgain();
if (error?.status_code === 403) return forbidden();Controle de acesso baseado em papéis cobre o que as duas dimensões significam e por que você geralmente deveria pedir um escopo.
signOut
signOut(scope?) → null
Encerra a sessão e limpa o armazenamento local.
await nulvless.auth.signOut(); // este dispositivo
await nulvless.auth.signOut('others'); // todos os outros
await nulvless.auth.signOut('global'); // todosscopeSignOutScopeOptionalQuais sessões encerrar. O padrão é local.
localSó esta. O padrão.globalToda sessão desta conta, em todo dispositivo.othersToda sessão menos esta.O global é o que um botão de "sair de todos os lugares" faz depois de uma troca
de senha. O others é a versão mais segura da mesma ideia quando a pessoa está
no dispositivo em que confia.
O armazenamento só é limpo quando a requisição dá certo, então um logout que falha deixa o client num estado consistente em vez de desautenticado localmente e vivo remotamente.
Captcha
Quando o ambiente protege um endpoint com captcha, a chamada precisa de um token
em options.captcha_token. Isso vale para lookup e signInWithOTP, signIn,
signUp e recover, cada um só se o grupo correspondente estiver ligado nas
configurações de captcha do ambiente.
Não é preciso mostrar o widget logo de início. Chame sem token e, só quando a
resposta for captcha_required ou captcha_verification_failed, mostre o
captcha e repita a chamada com o token que ele devolver:
const signIn = (captcha_token?: string) =>
nulvless.auth.signIn({ email, password, options: { captcha_token } });
let result = await signIn();
if (result.error?.code === 'captcha_required' || result.error?.code === 'captcha_verification_failed') {
const token = await showCaptcha();
result = await signIn(token);
}showCaptcha é o seu widget de Turnstile ou hCaptcha, configurado com a site
key que forma par com o secret definido no ambiente. Um token só é aceito uma
vez, então renderize o widget de novo a cada tentativa.