Rullst Connect is an elegant, async-first, and Developer Experience (DX) focused OAuth2 authentication library for Rust. It simplifies the integration of social logins into your Rust web applications, providing a standardized interface across multiple providers.
- π Async & Fast: Built on top of
tokioandreqwest. - π§© Standardized: All providers return a unified
ConnectUserstruct. - π‘οΈ Type-Safe: Robust error handling using
thiserror(ConnectError). - π Framework Agnostic: Works seamlessly with Rullst, Axum, Actix, Leptos, Dioxus, or any other framework.
- π Enterprise Security: Built-in OIDC Discovery, JWKS validation, and automated CSRF
tower-sessions. - πΊ Device Flow: Native RFC 8628 support for headless CLI and Smart TV auth.
- π οΈ Testing: Embedded Mock IdP router for seamless offline local E2E testing.
π Important Documents:
- CHANGELOG.md: See what's new.
- ISSUES: Any issue? Please report.
- ROADMAP.md: Discover our path.
- AUDIT.md: Complete security, performance, and maintainability audit report.
Official support for 11 core providers:
- GitHub
- Microsoft / Azure AD
- Apple (Sign in with Apple)
- Auth0
- AWS Cognito
- X (Twitter) (Strict PKCE requirement)
- Discord
- OIDC (OpenID Connect Custom Provider)
Add the package to your Cargo.toml. If you use Rullst, Axum, Actix, or Leptos, you can enable their specific features for native Extractor support!
You can either run:
cargo add rullst-connectOr manually add it to your Cargo.toml:
[dependencies]
rullst-connect = "10.0.1"
tokio = { version = "1.52", features = ["full"] }Choose your provider and pass your credentials and callback URL:
use rullst_connect::prelude::*;
let github = GithubProvider::new(
"YOUR_CLIENT_ID".to_string(),
"YOUR_CLIENT_SECRET".to_string(),
"http://localhost:3000/auth/github/callback".to_string(),
);Get the authorization URL and redirect your user:
let url = github.redirect_url();
// Example in Axum: return Redirect::temporary(&url);When the user returns to your callback URL with a code query parameter, exchange it for a ConnectUser:
let params = rullst_connect::provider::ExchangeParams {
auth_code: code,
..Default::default()
};
match github.get_user(params).await {
Ok(user) => {
println!("Welcome, {}!", user.name);
println!("Email: {:?}", user.email);
println!("Avatar: {:?}", user.avatar_url);
}
Err(_) => return (StatusCode::INTERNAL_SERVER_ERROR, "Failed to get user".to_string()),
}To prevent Cross-Site Request Forgery (CSRF) attacks, you should generate a secure random string, save it in a session/cookie, and pass it to the provider.
// 1. Generate a random state string and save it in the session
let state = "random_secure_string";
// 2. Get the authorization URL with the state parameter using the builder
let url = github.with_state(state).redirect_url();
// return Redirect::temporary(&url);
// 3. In the callback route, verify if the query param `state` matches your session!
// If you are using the optional `axum` or `actix` features, you can use `verify_state`:
// params.verify_state(&state_from_session)?;If an access token expires, you can seamlessly renew it without asking the user to login again by using their refresh_token:
let refreshed_user = github.refresh_token("existing_refresh_token_string").await?;
// Tokens are wrapped in `secrecy::SecretString` to prevent accidental log leakage ([REDACTED]).
// When you need to send it to an API, expose it explicitly:
use secrecy::ExposeSecret;
let raw_token = refreshed_user.access_token.expose_secret();
println!("Successfully refreshed token securely!");All providers natively support PKCE (Proof Key for Code Exchange) to mitigate authorization code interception attacks. Some providers like X (Twitter) v2 strictly require it.
use rullst_connect::pkce::generate_pkce;
// 1. Generate challenge and verifier
let (code_verifier, code_challenge) = generate_pkce();
// 2. Save `code_verifier` in the user's session or a secure HttpOnly cookie!
// 3. Get the URL with PKCE natively using the builder pattern
let auth_url = provider.with_pkce(&code_challenge).redirect_url();
// 4. In the callback route, fetch the user using the saved verifier:
let params = rullst_connect::provider::ExchangeParams {
auth_code: &code,
code_verifier: Some(&code_verifier),
..Default::default()
};
let user = provider.get_user(params).await.unwrap();You can find a complete working server using the Axum framework in the examples directory. Just run:
cargo run --example axum_serverThis project uses cargo-release to automate version bumps, README synchronization, and CHANGELOG management.
The publish workflow in .github/workflows/publish.yml runs when a vX.Y.Z tag is pushed, and it can also be triggered manually from GitHub Actions.
To release a new version, simply run:
# install it first if you haven't: cargo install cargo-release
cargo release patch --execute # for v1.0.x patches
cargo release minor --execute # for v1.x.0 features
cargo release major --execute # for vX.0.0 breaking changesThis will automatically bump versions, tag the release, and push to GitHub, triggering the crates.io publish workflow.
For the exact release checklist and what to do next time, see RELEASING.md.
Feel free to open Issues and submit Pull Requests! Want to add a new provider? It's easy! Just implement the Provider trait.
This project is licensed under the MIT License.