use better_auth::adapters::MemoryDatabaseAdapter;
use better_auth::plugins::{
AccountManagementPlugin, EmailPasswordPlugin, EmailVerificationPlugin, OrganizationPlugin,
PasswordManagementPlugin, SessionManagementPlugin,
};
use better_auth::types::{AuthRequest, HttpMethod};
use better_auth::{AuthBuilder, AuthConfig, BetterAuth};
use std::collections::HashMap;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Starting Better Auth Rust Example\n");
let config = AuthConfig::new("your-very-secure-secret-key-at-least-32-chars-long")
.base_url("http://localhost:3000")
.password_min_length(8);
let auth = AuthBuilder::new(config)
.database(MemoryDatabaseAdapter::new())
.plugin(EmailPasswordPlugin::new().enable_signup(true))
.plugin(PasswordManagementPlugin::new())
.plugin(EmailVerificationPlugin::new())
.plugin(SessionManagementPlugin::new())
.plugin(AccountManagementPlugin::new())
.plugin(OrganizationPlugin::new())
.build()
.await?;
println!("BetterAuth instance created");
println!("Registered plugins: {:?}\n", auth.plugin_names());
println!("=== Sign up with email and username ===");
let signup_body = serde_json::json!({
"email": "test@example.com",
"password": "password123",
"name": "Test User",
"username": "testuser",
"displayUsername": "Test User"
});
let response = send(
&auth,
HttpMethod::Post,
"/sign-up/email",
Some(&signup_body),
None,
)
.await;
println!("Status: {}", response.status);
let data = parse_body(&response.body);
let token = data["token"].as_str().unwrap_or_default().to_string();
println!("User: {}", data["user"]["email"]);
println!("Username: {}", data["user"]["username"]);
println!("Token: {}...\n", &token[..20.min(token.len())]);
println!("=== Sign in by email ===");
let signin_body = serde_json::json!({
"email": "test@example.com",
"password": "password123"
});
let response = send(
&auth,
HttpMethod::Post,
"/sign-in/email",
Some(&signin_body),
None,
)
.await;
println!("Status: {}\n", response.status);
println!("=== Sign in by username ===");
let signin_body = serde_json::json!({
"username": "testuser",
"password": "password123"
});
let response = send(
&auth,
HttpMethod::Post,
"/sign-in/username",
Some(&signin_body),
None,
)
.await;
println!("Status: {}", response.status);
let data = parse_body(&response.body);
println!("Logged in as: {}\n", data["user"]["email"]);
println!("=== Get session ===");
let response = send(&auth, HttpMethod::Get, "/get-session", None, Some(&token)).await;
println!("Status: {}", response.status);
let data = parse_body(&response.body);
println!("Session user: {}\n", data["user"]["email"]);
println!("=== List sessions ===");
let response = send(&auth, HttpMethod::Get, "/list-sessions", None, Some(&token)).await;
println!("Status: {}", response.status);
let data = parse_body(&response.body);
let session_count = data.as_array().map(|a| a.len()).unwrap_or(0);
println!("Active sessions: {}\n", session_count);
println!("=== Change password ===");
let body = serde_json::json!({
"currentPassword": "password123",
"newPassword": "newpassword456"
});
let response = send(
&auth,
HttpMethod::Post,
"/change-password",
Some(&body),
Some(&token),
)
.await;
println!("Status: {}\n", response.status);
println!("=== Change email ===");
let body = serde_json::json!({ "newEmail": "newemail@example.com" });
let response = send(
&auth,
HttpMethod::Post,
"/change-email",
Some(&body),
Some(&token),
)
.await;
println!("Status: {}", response.status);
let data = parse_body(&response.body);
println!("New email: {}\n", data["user"]["email"]);
println!("=== List accounts ===");
let response = send(&auth, HttpMethod::Get, "/list-accounts", None, Some(&token)).await;
println!("Status: {}", response.status);
let data = parse_body(&response.body);
let account_count = data.as_array().map(|a| a.len()).unwrap_or(0);
println!("Linked accounts: {}\n", account_count);
println!("=== Create organization ===");
let body = serde_json::json!({
"name": "Acme Corp",
"slug": "acme-corp"
});
let response = send(
&auth,
HttpMethod::Post,
"/organization/create",
Some(&body),
Some(&token),
)
.await;
println!("Status: {}", response.status);
let data = parse_body(&response.body);
let org_id = data["id"].as_str().unwrap_or_default().to_string();
println!("Organization: {} ({})", data["name"], data["slug"]);
println!("Org ID: {}\n", org_id);
println!("=== List organizations ===");
let response = send(
&auth,
HttpMethod::Get,
"/organization/list",
None,
Some(&token),
)
.await;
println!("Status: {}", response.status);
let data = parse_body(&response.body);
println!(
"Organizations: {}\n",
data.as_array().map(|a| a.len()).unwrap_or(0)
);
println!("=== Check slug availability ===");
let body = serde_json::json!({ "slug": "acme-corp" });
let response = send(
&auth,
HttpMethod::Post,
"/organization/check-slug",
Some(&body),
Some(&token),
)
.await;
println!("Status: {}", response.status);
let data = parse_body(&response.body);
println!("Slug 'acme-corp' available: {}\n", data["status"]);
println!("=== Set active organization ===");
let body = serde_json::json!({ "organizationId": org_id });
let response = send(
&auth,
HttpMethod::Post,
"/organization/set-active",
Some(&body),
Some(&token),
)
.await;
println!("Status: {}\n", response.status);
println!("=== Invite member ===");
let body = serde_json::json!({
"organizationId": org_id,
"email": "colleague@example.com",
"role": "member"
});
let response = send(
&auth,
HttpMethod::Post,
"/organization/invite-member",
Some(&body),
Some(&token),
)
.await;
println!("Status: {}", response.status);
let data = parse_body(&response.body);
println!("Invitation ID: {}\n", data["id"]);
println!("=== Update organization ===");
let body = serde_json::json!({
"organizationId": org_id,
"name": "Acme Corporation"
});
let response = send(
&auth,
HttpMethod::Post,
"/organization/update",
Some(&body),
Some(&token),
)
.await;
println!("Status: {}", response.status);
let data = parse_body(&response.body);
println!("Updated name: {}\n", data["name"]);
println!("=== Sign out ===");
let response = send(&auth, HttpMethod::Post, "/sign-out", None, Some(&token)).await;
println!("Status: {}", response.status);
let response = send(&auth, HttpMethod::Get, "/get-session", None, Some(&token)).await;
println!("Session after sign-out: {}\n", response.status);
println!("=== Invalid route ===");
let response = send(&auth, HttpMethod::Get, "/invalid-route", None, None).await;
println!("Status: {}\n", response.status);
println!("Example completed successfully!");
Ok(())
}
async fn send(
auth: &BetterAuth<MemoryDatabaseAdapter>,
method: HttpMethod,
path: &str,
body: Option<&serde_json::Value>,
bearer_token: Option<&str>,
) -> better_auth::types::AuthResponse {
let mut headers = HashMap::new();
if body.is_some() {
headers.insert("content-type".to_string(), "application/json".to_string());
}
if let Some(token) = bearer_token {
headers.insert("authorization".to_string(), format!("Bearer {}", token));
}
let request = AuthRequest::from_parts(
method,
path.to_string(),
headers,
body.map(|b| b.to_string().into_bytes()),
HashMap::new(),
);
auth.handle_request(request).await.unwrap()
}
fn parse_body(body: &[u8]) -> serde_json::Value {
serde_json::from_slice(body).unwrap_or(serde_json::Value::Null)
}