JWT e OAuth2
Emita e valide tokens de acesso JWT e integre fluxos de autorização OAuth2 para APIs Rust.
Receita
Cartão de referência rápida - pronto para copiar e colar.
use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation};
#[derive(serde::Serialize, serde::Deserialize)]
struct Claims { sub: String, exp: usize, aud: String }
let token = encode(&Header::default(), &claims, &EncodingKey::from_secret(secret))?;
let data = decode::<Claims>(&token, &DecodingKey::from_secret(secret), &Validation::default())?;Quando usar isso: Autenticação de API sem estado, propagação de identidade de microsserviços ou delegação de login para Google/Auth0 via OAuth2.
Exemplo de Trabalho
use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation};
use oauth2::{AuthUrl, ClientId, ClientSecret, RedirectUrl, TokenUrl, basic::BasicClient};
#[derive(serde::Serialize, serde::Deserialize)]
struct AccessClaims {
sub: String,
exp: usize,
aud: String,
}
fn issue_access_token(sub: &str, aud: &str, secret: &[u8], ttl_secs: usize) -> String {
let exp = (std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs()
+ ttl_secs as u64) as usize;
let claims = AccessClaims { sub: sub.into(), exp, aud: aud.into() };
encode(&Header::default(), &claims, &EncodingKey::from_secret(secret)).unwrap()
}
fn validate_access_token(token: &str, secret: &[u8], expected_aud: &str) -> Result<AccessClaims, jsonwebtoken::errors::Error> {
let mut validation = Validation::default();
validation.set_audience(&[expected_aud]);
let data = decode::<AccessClaims>(token, &DecodingKey::from_secret(secret), &validation)?;
Ok(data.claims)
}
fn oauth_client() -> BasicClient {
BasicClient::new(ClientId::new("client-id".into()))
.set_client_secret(ClientSecret::new("client-secret".into()))
.set_auth_uri(AuthUrl::new("https://issuer.example.com/oauth/authorize".into()).unwrap())
.set_token_uri(TokenUrl::new("https://issuer.example.com/oauth/token".into()).unwrap())
.set_redirect_uri(RedirectUrl::new("http://localhost:3000/callback".into()).unwrap())
}O que isso demonstra:
- Emissão e validação de token de acesso HS256 com
jsonwebtoken. - Validação de audiência (
aud) evita reutilização de token entre serviços. - Configuração de cliente
oauth2crate para fluxo de código de autorização. - Expiração (
exp) imposta porValidation.
Mergulho Profundo
Como Funciona
- JWT: claims JSON assinados; servidores verificam a assinatura e claims padrão.
- OAuth2: delega autenticação ao emissor; sua API valida tokens de acesso (geralmente JWT).
- Tokens de atualização permanecem confidenciais, com maior tempo de vida, armazenados de forma segura.
Seleção de Fluxo
| Fluxo | Uso |
|---|---|
| Credenciais do cliente | Máquina para máquina |
| Código de autorização + PKCE | Login de usuário para SPAs/mobile |
| Token de atualização | Renovar acesso sem novo login |
Notas de Rust
// RS256 com chave pública do OIDC JWKS
let key = DecodingKey::from_rsa_pem(public_pem)?;Armadilhas
- Segredo compartilhado HS256 entre serviços - Comprometimento vaza tudo. Correção: RS256 com JWKS por emissor.
- Pular verificações de aud/iss - Token de outro aplicativo aceito. Correção: Configurar audiência e emissor em
Validation. - Tokens de acesso de longa duração - Janela de roubo de token enorme. Correção: TTL curto (15m) + rotação de atualização.
- Parâmetro de estado OAuth omitido - CSRF no callback. Correção:
statealeatório armazenado na sessão. - Log de tokens - Aparecem nos logs de acesso. Correção: Redigir
Authorizationno tracing.
Alternativas
| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
| Cookies de sessão | Aplicativos focados em navegador | Clientes mobile/somente API |
| PASETO | Formato de token opinativo | Ecossistema espera JWT/OIDC |
| Chaves de API | Scripts internos | Usuários interativos |
FAQs
OIDC vs OAuth2?
OIDC adiciona identidade (id_token) ao OAuth2 - use para perfil de usuário.
Onde armazenar o token de atualização?
Cookie HttpOnly ou keystore mobile seguro - nunca localStorage.
Rotação de JWKS?
Cacheie chaves com TTL; refaça a busca em caso de incompatibilidade de kid.
Scopes?
Codifique em claims de token; imponha por handler.
Contas de serviço?
Fluxo de credenciais de cliente com JWT de curta duração.
Extrator Axum?
Veja a página Autenticação e Sessões para o padrão FromRequestParts.
Assimetria de relógio?
validation.leeway segundos para exp/nbf.
Logout?
Lista negra de tokens até exp ou servidor de sessão para revogação de atualização.
Testes?
Chaves de teste estáticas; helper encode no módulo de teste.
Auth0/Keycloak?
Use o URL de metadados do emissor; valide RS256 contra JWKS publicado.
Relacionado
- Autenticação e Sessões - Guardas Axum
- Hashing de Senhas - Credenciais locais
- Gerenciamento de Segredos - Chaves de assinatura
- APIs e Melhores Práticas de Segurança - Base de autenticação
- Criptografia (ring / RustCrypto) - Primitivas de assinatura
Versões do Stack: Esta página foi escrita para Rust 1.97.0 (edição 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, e Polars 0.46+.