10 exemplos para você começar com autenticação móvel - 7 básicos e 3 intermediários. Abrange modelos de sessão, onde os tokens residem no dispositivo e o que significa logout em todos os lugares quando os usuários trocam de conta ou revogam o acesso.
Aplicativos móveis geralmente usam uma das três formas de sessão. Escolha com base no seu backend - não invente uma quarta, a menos que a conformidade exija.
┌─────────────────────────────────────────────────────────────────┐│ Modelo │ Token de acesso │ Refresh │ Sessão do servidor │├────────────────────┼─────────────────┼─────────┼────────────────────┤│ JWT + refresh │ JWT Curto │ Rotativo│ sid Opcional ││ Portador opaco │ Token opaco │ Rotativo│ Obrigatório ││ Cookie (raro RN) │ HttpOnly* │ HttpOnly│ Obrigatório │└────────────────────┴─────────────────┴─────────┴────────────────────┘* Cookies HttpOnly são complicados em RN - prefira o cabeçalho Authorization + armazenamento seguro.
// src/features/auth/model/session.tsexport type Session = { accessToken: string; refreshToken: string; expiresAt: number; // ms epoch - dica apenas do lado do cliente; o servidor valida userId: string;};
JWT + refresh é o padrão Expo mais comum - token de acesso na memória ou armazenamento seguro, token de refresh apenas no armazenamento seguro
Portador opaco empurra a validação inteiramente para o lado do servidor - o cliente armazena strings opacas, nunca analisa as reivindicações
Sessões de cookie em React Native exigem "cookie jars" e são frágeis com deep links - evite, a menos que você possua uma pilha de cookies madura
Trate expiresAt como uma dica do cliente para refresh proativo - o relógio do servidor é o autoritário
Tokens de acesso autorizam chamadas de API. Tokens de refresh obtêm novos tokens de acesso - eles têm um valor mais alto e devem ser armazenados com mais cuidado.
Camadas de armazenamento móvel têm modelos de ameaça diferentes. Combine a sensibilidade com a loja.
┌──────────────────┬────────────────────────────────────────────────┐│ Armazenamento │ Apropriado para │├──────────────────┼────────────────────────────────────────────────┤│ Estado do React │ Token de acesso na memória durante a sessão ativa ││ expo-secure-store│ Tokens de refresh, segredos de longa duração ││ AsyncStorage │ Tema, sinalizadores de onboarding, preferências não sensíveis ││ MMKV (criptografado) │ Grandes caches - não um substituto para Keychain ││ expo-file-system │ Arquivos, mídia - nunca tokens brutos │└──────────────────┴────────────────────────────────────────────────┘
import * as SecureStore from "expo-secure-store";const REFRESH_KEY = "auth.refresh_token";export async function saveRefreshToken(token: string) { await SecureStore.setItemAsync(REFRESH_KEY, token, { keychainAccessible: SecureStore.WHEN_UNLOCKED_THIS_DEVICE_ONLY, });}export async function loadRefreshToken() { return SecureStore.getItemAsync(REFRESH_KEY);}
Secure Store mapeia para iOS Keychain e Android Keystore - com suporte de hardware em dispositivos compatíveis
AsyncStorage é SQLite não criptografado - bom para hasSeenOnboarding, fatal para tokens de refresh
Tokens de acesso na memória desaparecem ao encerrar o processo - combine com refresh silencioso ao iniciar a frio
Audite PRs para AsyncStorage.setItem com nomes de chaves semelhantes a tokens
O logout local limpa os artefatos do dispositivo e o estado na memória. É o mínimo que todo aplicativo deve implementar.
// src/features/auth/api/signOutLocal.tsimport * as SecureStore from "expo-secure-store";const AUTH_KEYS = ["auth.refresh_token", "auth.device_binding_id"] as const;export async function signOutLocal() { await Promise.all(AUTH_KEYS.map((key) => SecureStore.deleteItemAsync(key)));}
// Na sua tela de configuraçõesimport { useAuth } from "../AuthProvider";import { signOutLocal } from "../api/signOutLocal";async function handleSignOut() { await signOutLocal(); setSession(null); // do setter de estado do AuthProvider exposto via contexto router.replace("/sign-in");}
Exclua todas as chaves do armazenamento seguro que seu fluxo de autenticação gravou - refresh, ID de vinculação do dispositivo, sinalizadores de desbloqueio biométrico
Redefina a navegação para a pilha de login - o botão voltar do Android não deve retornar às telas autenticadas
Limpar apenas o estado do React é insuficiente - os usuários relançam em um shell autenticado com tokens obsoletos
Combine com queryClient.clear() do TanStack Query quando caches com backup de servidor contiverem PII do usuário
Se os usuários fazem login com e-mail ou Google, normalize para um único tipo Session para que o restante do aplicativo permaneça independente do provedor.
Devo armazenar o token de acesso no armazenamento seguro também?
Na memória é suficiente para a maioria dos aplicativos se a inicialização a frio sempre fizer refresh.
Persista o token de acesso apenas quando seu backend não puder fazer refresh frequentemente e a UX exigir leituras offline - ainda prefira um TTL curto.
O Expo Go é seguro para testar fluxos de autenticação?
URIs de redirecionamento OAuth diferem entre Expo Go e builds standalone - teste em um build de desenvolvimento antes do lançamento.
Secure Store funciona no Expo Go, mas esquemas de URL personalizados para OAuth exigem configuração de redirecionamento expo-auth-session por ambiente.
Qual é a diferença entre logout e revogação?
Logout limpa este dispositivo.
Revogar / logout em todos os lugares invalida os tokens de refresh no lado do servidor para todos os dispositivos - necessário para cenários de roubo de dispositivo.
Posso usar reivindicações JWT para autorização no cliente?
Decodifique reivindicações apenas para UX (exibir nome, avatar).
Nunca confie em verificações do lado do cliente para segurança - o servidor valida cada requisição.
Onde vão as chaves de API?
Chaves públicas em EXPO_PUBLIC_* apenas se projetadas para exposição ao cliente.
Nunca coloque segredos de cliente OAuth no aplicativo - troque códigos no seu backend.