OAuth 2.0 and JWT Authorization in Rust: Step-by-Step Guide

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction: Why OAuth 2.0 and JWT in Rust?

\n\n

Modern web applications rarely do without an authentication and authorization system. OAuth 2.0 is the industry standard for delegated access, and JWT (JSON Web Tokens) is a compact and secure way to transfer claims between parties. Rust, thanks to its performance and memory safety, is becoming increasingly popular for building high-load servers. In this article, we will practically explore how to implement OAuth 2.0 authorization with JWT in Rust, using popular crates and modern approaches.

\n\n

1. Project Setup and Dependency Installation

\n\n

First, let's create a new Rust project and add the necessary dependencies. We will use actix-web for the web server, jsonwebtoken for working with JWT, serde for serialization, and reqwest for HTTP requests to external OAuth providers.

\n\n
# 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\n

Let's create a .env file to store secret keys:

\n\n
JWT_SECRET=your_super_secret_key_here\nGITHUB_CLIENT_ID=your_github_client_id\nGITHUB_CLIENT_SECRET=your_github_client_secret
\n\n

2. Basic JWT Token Structure

\n\n

JWT consists of three parts: header, payload, and signature. Let's define the structures for working with 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,       // user identifier\n    pub email: String,     // user email\n    pub exp: usize,        // expiration time\n    pub iat: usize,        // issued at time\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 lives for 24 hours\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\n

3. Implementing OAuth 2.0 with GitHub

\n\n

Let's consider the classic OAuth 2.0 scenario — authorization via GitHub. The user is redirected to GitHub, after confirmation receives a code, which we exchange for an access token.

\n\n

3.1. Endpoint to Start the OAuth Flow

\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                

Blogs

Book Recommendations