OAuth клиент для Rust: библиотека oauth2

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

OAuth клиент для Rust: библиотека oauth2

OAuth 2.0 – это отраслевой стандарт для делегирования доступа. Он широко используется для авторизации пользователей через сторонние сервисы (Google, GitHub, Facebook) без передачи пароля. В экосистеме Rust одной из самых популярных и зрелых библиотек для реализации OAuth 2.0 является oauth2 (crate oauth2). Она предоставляет безопасный, асинхронный и гибкий API для работы с любыми OAuth-провайдерами.

Основные возможности

  • Поддержка всех стандартных грантов: Authorization Code, Client Credentials, Resource Owner Password Credentials, Implicit.
  • Встроенная поддержка PKCE (Proof Key for Code Exchange) для повышения безопасности публичных клиентов.
  • Асинхронная работа с использованием reqwest или ureq под капотом.
  • Типобезопасность: все токены, URL и параметры строго типизированы, исключая ошибки на этапе компиляции.
  • Гибкая настройка под любого провайдера через конфигурацию эндпоинтов и scopes.
  • Работа с токенами: автоматическое обновление (refresh), проверка истечения срока действия.

Установка

Добавьте зависимость в ваш Cargo.toml:

[dependencies]
oauth2 = "4.4"
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
reqwest = { version = "0.11", features = ["json"] }

Базовый пример: авторизация через Google

Рассмотрим полный цикл OAuth 2.0 с грантом Authorization Code + PKCE для 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. Создаём клиент с настройками от Google
    let client = BasicClient::new(
        ClientId::new("ВАШ_GOOGLE_CLIENT_ID".to_string()),
        Some(ClientSecret::new("ВАШ_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. Генерируем PKCE challenge
    let (pkce_challenge, pkce_verifier) = PkceCodeChallenge::new_random_sha256();

    // 3. Строим URL для авторизации пользователя
    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!("Откройте в браузере: {}", auth_url);

    // 4. (Симуляция) получаем код авторизации от пользователя
    let code = "код_из_браузера_после_редиректа";

    // 5. Обмениваем код на токен
    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(())
}

Продвинутые сценарии

1. Обновление токена (Refresh Token)

Когда access token истекает, используйте refresh token для получения нового:

use oauth2::RefreshToken;

let refresh_token = RefreshToken::new("ваш_рефреш_токен".to_string());
let new_token = client
    .exchange_refresh_token(&refresh_token)
    .request_async(async_http_client)
    .await?;

println!("Новый access token: {}", new_token.access_token().secret());

2. Клиентские учётные данные (Client Credentials)

Подходит для сервер-серверных сценариев (например, API-ключи):

use oauth2::ClientCredentialsToken;

let token = client
    .exchange_client_credentials()
    .add_scope(Scope::new("api.read".to_string()))
    .request_async(async_http_client)
    .await?;

println!("Client credentials token: {}", token.access_token().secret());

3. Парольный

Рекомендаций