Introduction : pourquoi OAuth 2.0 et JWT en Rust ?
\n\nLes applications web modernes ne se passent que rarement d'un système d'authentification et d'autorisation. OAuth 2.0 est la norme industrielle pour la délégation d'accès, et JWT (JSON Web Tokens) est un moyen compact et sécurisé de transmettre des assertions entre les parties. Rust, grâce à ses performances et à sa sécurité mémoire, devient de plus en plus populaire pour créer des serveurs à forte charge. Dans cet article, nous allons voir en pratique comment implémenter l'autorisation OAuth 2.0 avec JWT en Rust, en utilisant des crates populaires et des approches modernes.
\n\n1. Préparation du projet et installation des dépendances
\n\nPour commencer, créons un nouveau projet Rust et ajoutons les dépendances nécessaires. Nous utiliserons actix-web pour le serveur web, jsonwebtoken pour travailler avec JWT, serde pour la sérialisation et reqwest pour les requêtes HTTP vers les fournisseurs OAuth externes.
# 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\nCréons un fichier .env pour stocker les clés secrètes :
JWT_SECRET=votre_clé_super_secrète_ici\nGITHUB_CLIENT_ID=votre_identifiant_client_github\nGITHUB_CLIENT_SECRET=votre_secret_client_github\n\n2. Structure de base des jetons JWT
\n\nUn JWT se compose de trois parties : l'en-tête, la charge utile et la signature. Définissons les structures pour travailler avec les jetons.
\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, // identifiant utilisateur\n pub email: String, // email utilisateur\n pub exp: usize, // date d'expiration\n pub iat: usize, // date d'émission\n}\n\npub fn create_jwt(user_id: &str, email: &str) -> Result {\n let now = Utc::now();\n let expiration = now + Duration::hours(24); // le jeton est valide 24 heures\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 doit être défini");\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 doit être défini");\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. Implémentation d'OAuth 2.0 avec GitHub
\n\nExaminons le scénario classique d'OAuth 2.0 — l'autorisation via GitHub. L'utilisateur est redirigé vers GitHub, après confirmation il reçoit un code que nous échangeons contre un jeton d'accès.
\n\n3.1. Point de terminaison pour démarrer le flux 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