Cliente OAuth para Rust: biblioteca oauth2-rs

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Biblioteca oauth2-rs: implementación de OAuth 2.0 en Rust

\n\n

En el desarrollo web moderno, OAuth 2.0 es el protocolo estándar para la delegación de acceso. La biblioteca oauth2-rs proporciona una implementación completa de un cliente OAuth 2.0 en el lenguaje Rust. Permite integrar la autenticación a través de servicios populares: Google, GitHub, Yandex, VK y otros.

\n\n

Esta biblioteca soporta todos los flujos (flows) clave: Authorization Code, Client Credentials, Implicit, así como Refresh Token. Se presta especial atención a la seguridad: se utiliza PKCE (Proof Key for Code Exchange) para clientes públicos y la validación obligatoria de tokens.

\n\n

Instalación de oauth2-rs

\n\n

Agregue la dependencia en Cargo.toml:

\n\n
[dependencies]\noauth2 = "4.4"\ntokio = { version = "1", features = ["full"] }\nreqwest = { version = "0.11", features = ["json"] }\nserde = { version = "1.0", features = ["derive"] }
\n\n

También se necesitará un cliente HTTP (se recomienda reqwest con soporte async) y el serializador serde para trabajar con JSON.

\n\n

Configuración básica del cliente OAuth

\n\n

Consideremos un ejemplo para Google OAuth 2.0. Primero, crearemos la configuración:

\n\n
use oauth2::{\n    AuthorizationCode, AuthUrl, ClientId, ClientSecret, \n    RedirectUrl, TokenUrl, CsrfToken, Scope,\n    basic::BasicClient, TokenResponse\n};\n\nlet client_id = ClientId::new("YOUR_GOOGLE_CLIENT_ID".to_string());\nlet client_secret = ClientSecret::new("YOUR_GOOGLE_CLIENT_SECRET".to_string());\nlet auth_url = AuthUrl::new("https://accounts.google.com/o/oauth2/v2/auth".to_string())\n    .expect("Invalid auth URL");\nlet token_url = TokenUrl::new("https://oauth2.googleapis.com/token".to_string())\n    .expect("Invalid token URL");\n\nlet client = BasicClient::new(\n    client_id,\n    Some(client_secret),\n    auth_url,\n    Some(token_url)\n).set_redirect_uri(\n    RedirectUrl::new("http://localhost:8080/callback".to_string())\n        .expect("Invalid redirect URL")\n);
\n\n

Generación de la URL de autorización

\n\n

Creamos un enlace al que se debe redirigir al usuario:

\n\n
let (auth_url, csrf_token) = client\n    .authorize_url(CsrfToken::new_random)\n    .add_scope(Scope::new("openid".to_string()))\n    .add_scope(Scope::new("email".to_string()))\n    .url();\n\nprintln!("Vaya al enlace: {}", auth_url);\n// Guarde csrf_token para verificarlo en el callback
\n\n

CsrfToken protege contra ataques de falsificación de solicitudes entre sitios (CSRF). Debe almacenarse temporalmente (por ejemplo, en una sesión o cookies) y verificarse al procesar el callback.

\n\n

Manejo del callback y obtención del token

\n\n

Después de que el usuario confirme el acceso, el servicio lo redirigirá a la redirect_uri con el parámetro code. Ejemplo de un manejador en Rust:

\n\n
use actix_web::{web, HttpRequest, HttpResponse};\nuse oauth2::AuthorizationCode;\n\nasync fn callback(query: web::Query<std::collections::HashMap<String, String>>) -> HttpResponse {\n    let code = query.get("code")\n        .expect("Falta el código de autorización");\n    let state = query.get("state")\n        .expect("Falta el estado");\n\n    // Verificar state contra el csrf_token guardado\n    // ...\n\n    let token_result = client\n        .exchange_code(AuthorizationCode::new(code.clone()))\n        .request_async(&reqwest::Client::new())\n        .await;\n\n    match token_result {\n        Ok(token) => {\n            let access_token = token.access_token().secret();\n            let refresh_token = token.refresh_token()\n                .map(|rt| rt.secret().clone());\n            // Guardar tokens en la BD o sesión\n            HttpResponse::Ok().body("¡Autorización exitosa!")\n        },\n        Err(e) => {\n            eprintln!("Error al intercambiar el código: {:?}", e);\n            HttpResponse::InternalServer                    

Recommendations