Module oauth2

Module oauth2 

Source
Expand description

OAuth2 login flow with /login and /callback routes. Cookie templates are validated when building routes to fail fast on insecure combinations.

Example: insert account before JWT using a repository (ensures stable account_id in cookie)

use axum_gate::prelude::*;
use axum_gate::repositories::memory::MemoryAccountRepository;
use std::sync::Arc;

let jwt_codec = Arc::new(JsonWebToken::<JwtClaims<Account<Role, Group>>>::default());

// Build an account repository (e.g., in-memory for examples)
let account_repo = Arc::new(MemoryAccountRepository::<Role, Group>::default());

// Configure gate with repository-backed insertion before JWT issuance
let gate = Gate::oauth2::<Role, Group>()
    .auth_url("https://provider.example.com/oauth2/authorize")
    .token_url("https://provider.example.com/oauth2/token")
    .client_id("CLIENT_ID")
    .client_secret("CLIENT_SECRET")
    .redirect_url("http://localhost:3000/auth/callback")
    .add_scope("openid")
    // Provide JWT codec and TTL as usual
    .with_jwt_codec("my-app", jwt_codec, 60 * 60 * 24)
    // Persist or load the account before encoding the JWT
    .with_account_repository(Arc::clone(&account_repo))
    // Map provider tokens to your domain account (e.g., via userinfo)
    .with_account_mapper(|_token| {
        Box::pin(async move {
            Ok(Account::<Role, Group>::new("user@example.com", &[Role::User], &[]))
        })
    });

This module provides an OAuth2Gate builder that mounts routes to perform an Authorization Code + PKCE flow. On successful callback, it can:

  • Map the token response to an Account<R, G> via a user-supplied mapper
  • Mint a first-party JWT via a user-supplied codec (helper provided)
  • Optionally insert or load the account before issuing the JWT (via with_account_repository or with_account_inserter) so the cookie includes a stable account_id
  • Set a secure auth cookie using the crate’s cookie template
  • Optionally redirect to a configured post-login URL

Usage (minimal):

  • Configure the gate (auth url, token url, client credentials, redirect url, scopes)
  • Provide an account mapper and JWT codec to issue a first-party session
  • Optionally provide an account inserter or repository to persist/load an account before JWT, ensuring a stable account_id in the session cookie
  • Mount its routes under a base path like /auth

Example (issuing first-party cookie):

use axum::{Router, routing::get};
use axum_gate::prelude::*;
use std::sync::Arc;

let jwt_codec = Arc::new(JsonWebToken::<JwtClaims<Account<Role, Group>>>::default());

let gate = Gate::oauth2::<Role, Group>()
    .auth_url("https://provider.example.com/oauth2/authorize")
    .token_url("https://provider.example.com/oauth2/token")
    .client_id("CLIENT_ID")
    .client_secret("CLIENT_SECRET") // optional for public clients
    .redirect_url("http://localhost:3000/auth/callback")
    .add_scope("openid")
    .with_post_login_redirect("/")
    .with_jwt_codec("my-app", Arc::clone(&jwt_codec), 60 * 60 * 24) // 24h TTL
    .with_account_mapper(|_token| {
        // Map provider token response to your domain Account<R, G>.
        // For plain OAuth2, you might call the provider's userinfo API here.
        // Example (pseudo):
        // let user = fetch_userinfo(token.access_token())?;
        // Ok(Account::new(&user.email, &[Role::User], &[]))
        Box::pin(async move {
            Ok(Account::<Role, Group>::new("user@example.com", &[Role::User], &[]))
        })
    });

// routes() returns Result<Router<()>, OAuth2Error>; handle or unwrap as needed
let auth_router = gate.routes("/auth").expect("valid OAuth2 config");
let app = Router::<()>::new().nest("/auth", auth_router);

Security and cookie configuration:

  • State and PKCE cookies use secure, short-lived, HttpOnly defaults with SameSite=Lax (good for OAuth redirects).
  • You can fully customize state/PKCE cookie attributes (name, path, domain, SameSite, Secure, HttpOnly, Max-Age) via CookieTemplate helpers on the builder.
  • The first-party auth cookie template remains configurable via with_cookie_template or configure_cookie_template.

Example: customize state/PKCE cookies

use axum_gate::prelude::*;
use cookie::{SameSite, time::Duration};

let gate = Gate::oauth2::<Role, Group>()
    // ... provider endpoints and client config ...
    // Optional: custom names (multi-provider setups)
    .with_cookie_names("my-oauth-state", "my-oauth-pkce")
    // Optional: fine-tune state cookie (shorter TTL, SameSite)
    .configure_state_cookie_template(|t| {
        t.same_site(SameSite::Lax)
         .max_age(Duration::minutes(5))
    })
    .unwrap()
    // Optional: fine-tune PKCE cookie similarly
    .configure_pkce_cookie_template(|t| {
        t.same_site(SameSite::Lax)
         .max_age(Duration::minutes(5))
    })
    .unwrap();

Note: In production, serve over HTTPS and prefer Secure=true. If you set SameSite=None you must also set Secure=true (browser enforcement); CookieTemplate::validate() guards against insecure combinations.

Modules§

errors
OAuth2 errors for gate::oauth2.

Structs§

OAuth2Gate
Public builder for configuring OAuth2 routes and session issuance.