Introdução: por que OAuth 2.0 e JWT em Rust?
\n\nAs aplicações web modernas raramente funcionam sem um sistema de autenticação e autorização. OAuth 2.0 é o padrão da indústria para delegação de acesso, e JWT (JSON Web Tokens) é uma forma compacta e segura de transmitir declarações entre partes. Rust, graças ao seu desempenho e segurança de memória, está se tornando cada vez mais popular para a criação de servidores de alta carga. Neste artigo, vamos abordar na prática como implementar autorização OAuth 2.0 com JWT em Rust, usando crates populares e abordagens modernas.
\n\n1. Preparação do projeto e instalação de dependências
\n\nPara começar, vamos criar um novo projeto em Rust e adicionar as dependências necessárias. Usaremos actix-web para o servidor web, jsonwebtoken para trabalhar com JWT, serde para serialização e reqwest para requisições HTTP a provedores OAuth externos.
# Cargo.toml\n[package]\nname = "oauth-jwt-rust"\nversion = "0.1.0"\nedition = "2021"\n\n[dependencies]\nactix-web = "4"\nactix-rt = "2"\njsonwebtoken = "9"\nserde = { version = "1.0", features = ["derive"] }\nserde_json = "1.0"\nreqwest = { version = "0.12", features = ["json"] }\ntokio = { version = "1", features = ["full"] }\ndotenv = "0.15"\nchrono = { version = "0.4", features = ["serde"] }\nuuid = { version = "1", features = ["v4"] }\n\nVamos criar o arquivo .env para armazenar as chaves secretas:
JWT_SECRET=your_super_secret_key_here\nGITHUB_CLIENT_ID=your_github_client_id\nGITHUB_CLIENT_SECRET=your_github_client_secret\n\n2. Estrutura básica dos tokens JWT
\n\nO JWT consiste em três partes: cabeçalho, payload e assinatura. Vamos definir as estruturas para trabalhar com os tokens.
\n\n// src/jwt.rs\nuse chrono::{Utc, Duration};\nuse jsonwebtoken::{encode, decode, Header, Validation, EncodingKey, DecodingKey};\nuse serde::{Deserialize, Serialize};\n\n#[derive(Debug, Serialize, Deserialize)]\npub struct Claims {\n pub sub: String, // identificador do usuário\n pub email: String, // email do usuário\n pub exp: usize, // tempo de expiração\n pub iat: usize, // tempo de emissão\n}\n\npub fn create_jwt(user_id: &str, email: &str) -> Result {\n let now = Utc::now();\n let expiration = now + Duration::hours(24); // token válido por 24 horas\n\n let claims = Claims {\n sub: user_id.to_string(),\n email: email.to_string(),\n exp: expiration.timestamp() as usize,\n iat: now.timestamp() as usize,\n };\n\n let secret = std::env::var("JWT_SECRET").expect("JWT_SECRET must be set");\n encode(\n &Header::default(),\n &claims,\n &EncodingKey::from_secret(secret.as_bytes()),\n )\n}\n\npub fn validate_jwt(token: &str) -> Result {\n let secret = std::env::var("JWT_SECRET").expect("JWT_SECRET must be set");\n let token_data = decode::(\n token,\n &DecodingKey::from_secret(secret.as_bytes()),\n &Validation::default(),\n )?;\n Ok(token_data.claims)\n} \n\n3. Implementação do OAuth 2.0 com GitHub
\n\nVamos considerar o cenário clássico do OAuth 2.0 — autorização via GitHub. O usuário é redirecionado para o GitHub, após a confirmação recebe um código que trocamos por um access token.
\n\n3.1. Endpoint para iniciar o fluxo OAuth
\n\n// src/oauth.rs\nuse actix_web::{web, HttpResponse, HttpRequest};\nuse reqwest::Client;\nuse serde_json::Value;\n\npub async fn github_login() -> HttpResponse {\n let client_id = std::env::var("GITHUB_CLIENT_ID").unwrap();\n let redirect_uri = "http://localhost:8080/auth/github/callback";\n \n let auth_url = format!(\n "https://github.com/login/oauth/authorize?client_id={}&redirect_uri={}&scope=user:email",\n client_id, redirect_uri\n );\n \n HttpRes