Cliente OAuth para Rust: biblioteca oauth2
OAuth 2.0 é o padrão da indústria para delegação de acesso. É amplamente utilizado para autorizar usuários através de serviços terceiros (Google, GitHub, Facebook) sem compartilhar senhas. No ecossistema Rust, uma das bibliotecas mais populares e maduras para implementar OAuth 2.0 é a oauth2 (crate oauth2). Ela fornece uma API segura, assíncrona e flexível para trabalhar com qualquer provedor OAuth.
Principais recursos
- Suporte a todos os grants padrão: Authorization Code, Client Credentials, Resource Owner Password Credentials, Implicit.
- Suporte nativo a PKCE (Proof Key for Code Exchange) para aumentar a segurança de clientes públicos.
- Operação assíncrona usando
reqwestouureqinternamente. - Segurança de tipos: todos os tokens, URLs e parâmetros são estritamente tipados, eliminando erros em tempo de compilação.
- Configuração flexível para qualquer provedor através da configuração de endpoints e scopes.
- Gerenciamento de tokens: renovação automática (refresh), verificação de expiração.
Instalação
Adicione a dependência ao seu Cargo.toml:
[dependencies]oauth2 = "4.4"tokio = { version = "1", features = ["full"] }serde = { version = "1", features = ["derive"] }reqwest = { version = "0.11", features = ["json"] }Exemplo básico: autorização via Google
Vamos ver o ciclo completo do OAuth 2.0 com o grant Authorization Code + PKCE para o Google:
use oauth2::{ AuthorizationCode, AuthUrl, ClientId, ClientSecret, CsrfToken, PkceCodeChallenge, RedirectUrl, Scope, TokenResponse, TokenUrl,};use oauth2::basic::BasicClient;use oauth2::reqwest::async_http_client;use url::Url;
#[tokio::main]async fn main() -> Result<(), Box> { // 1. Criando o cliente com as configurações do Google let client = BasicClient::new( ClientId::new("SEU_GOOGLE_CLIENT_ID".to_string()), Some(ClientSecret::new("SEU_GOOGLE_CLIENT_SECRET".to_string())), AuthUrl::new("https://accounts.google.com/o/oauth2/v2/auth".to_string())?, Some(TokenUrl::new("https://oauth2.googleapis.com/token".to_string())?), ) .set_redirect_uri(RedirectUrl::new("http://localhost:8080/callback".to_string())?);
// 2. Gerando o desafio PKCE let (pkce_challenge, pkce_verifier) = PkceCodeChallenge::new_random_sha256();
// 3. Construindo a URL para autorização do usuário let (auth_url, csrf_token) = client .authorize_url(CsrfToken::new_random) .add_scope(Scope::new("openid".to_string())) .add_scope(Scope::new("profile".to_string())) .add_scope(Scope::new("email".to_string())) .set_pkce_challenge(pkce_challenge) .url();
println!("Abra no navegador: {}", auth_url);
// 4. (Simulação) obtendo o código de autorização do usuário let code = "codigo_do_navegador_apos_redirecionamento";
// 5. Trocando o código pelo token let token_response = client .exchange_code(AuthorizationCode::new(code.to_string())) .set_pkce_verifier(pkce_verifier) .request_async(async_http_client) .await?;
println!("Access token: {}", token_response.access_token().secret()); println!("Refresh token: {:?}", token_response.refresh_token());
Ok(())} Cenários avançados
1. Renovação de token (Refresh Token)
Quando o access token expirar, use o refresh token para obter um novo:
use oauth2::RefreshToken;
let refresh_token = RefreshToken::new("seu_refresh_token".to_string());let new_token = client .exchange_refresh_token(&refresh_token) .requ