Eventos
Reagir a entrada, saída, renovação de token e sudo, onde quer que aconteçam.
A autenticação muda em lugares que os seus componentes não iniciaram: um token renova por tempo, uma renovação é rejeitada enquanto a pessoa lê a tela, outra aba faz logout. Os eventos são como o resto da sua aplicação fica sabendo.
Eventos existem apenas no client de navegador. O createServerClient não
tem on() — um servidor não guarda sessão que mude, então não há o que
transmitir.
on
on(event, handler) → () => void
Assina, e devolve a função que cancela a assinatura. Devolva ela de um effect e o framework cuida da limpeza:
useEffect(() => {
const off = nulvless.auth.on('signed-in', (session) => {
setUser(session.user);
});
return off;
}, []);Esquecer de cancelar a assinatura é o bug clássico aqui — um componente que remonta dez vezes acaba tratando cada evento dez vezes.
Um handler que lança erro é registrado no console e ignorado. Os outros handlers
continuam rodando, e a chamada que emitiu o evento — um signIn, uma renovação —
não é afetada.
const offIn = nulvless.auth.on('signed-in', (session) => setUser(session.user));
const offOut = nulvless.auth.on('signed-out', () => setUser(null));
const offDead = nulvless.auth.on('unauthorized', () => setUser(null));
// mais tarde
offIn();
offOut();
offDead();Os eventos
signed-inAuthenticatedUma entrada ou cadastro deu certo e o token foi guardado. Carrega a sessão completa, então você raramente precisa buscar algo no handler.
signed-out{ userId? }O signOut deu certo. Dispara depois que o servidor confirma, não quando você
chama — um logout que falha não emite nada, e o client segue consistente.
challengeAuthenticatedO servidor respondeu com um desafio e nenhum token: MFA, um passo de OTP, uma confirmação de cadastro. Útil para rotear para a tela de verificação de um lugar só, em vez de em cada ponto de chamada.
token-refreshedAuthenticatedO access token foi renovado em segundo plano — nesta aba ou em outra aba do mesmo projeto. Você não precisa agir sobre isso — está aí para log, ou para reenviar um token que você entregou a outra coisa.
unauthorizedAuthenticatedO SDK não consegue mais autenticar: não há refresh token, ou uma renovação foi rejeitada. Este é o sinal de sessão-acabou — limpe seu estado e mande para a tela de entrada.
payloadCarrega a sessão que falhou, incluindo o user dela quando conhecido,
para uma aplicação multi-conta remover a entrada certa.
sudo-requiredvoidUma requisição falhou com 403 protected_action_denied. Comece o fluxo de
sudo e repita. Sem payload — o evento é a mensagem inteira.
account-switched{ userId }O auth.switch() deu certo. Só faz sentido com multi-conta habilitado.
Os dois que mais importam
Todo o resto é opcional. Estes dois não são:
nulvless.auth.on('unauthorized', () => {
clearAppState();
router.push('/sign-in');
});
nulvless.auth.on('sudo-required', async () => {
await nulvless.auth.sessions.sudo();
openSudoPrompt();
});Vale ter um handler de token-refreshed quando algo fora do SDK segura o token:
nulvless.auth.on('token-refreshed', (session) => {
socket.updateAuth(session.access_token);
});O unauthorized é a única forma confiável de saber que a sessão morreu sem você
ter feito nada — ficar consultando getSession é mais lento e ainda por cima
errado. E tratar sudo-required de forma centralizada significa nunca precisar
lembrar quais chamadas são protegidas, o que é configuração por ambiente e não
está sob seu controle.
unauthorized não é a mesma coisa que um 401 de uma chamada. Um 401 isolado
pode significar só um access token expirado, que o SDK renova e repete. Este
evento dispara apenas depois que a renovação falhou — a sessão acabou de fato.