use axum::{Json, Router, response::IntoResponse, routing::get};
use better_auth::adapters::MemoryDatabaseAdapter;
use better_auth::handlers::{AxumIntegration, CurrentSession, OptionalSession};
use better_auth::plugins::{
AccountManagementPlugin, EmailPasswordPlugin, OrganizationPlugin, PasswordManagementPlugin,
SessionManagementPlugin,
};
use better_auth::{AuthBuilder, AuthConfig, AuthUser, BetterAuth};
use std::sync::Arc;
use tokio::net::TcpListener;
use tower_http::cors::CorsLayer;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::fmt::init();
println!("🚀 Starting Better Auth Axum Server");
let config = AuthConfig::new("your-very-secure-secret-key-at-least-32-chars-long")
.base_url("http://localhost:8080")
.password_min_length(6);
println!("📋 Configuration created");
let database = MemoryDatabaseAdapter::new();
let auth = Arc::new(
AuthBuilder::new(config)
.database(database)
.plugin(EmailPasswordPlugin::new().enable_signup(true))
.plugin(SessionManagementPlugin::new())
.plugin(PasswordManagementPlugin::new())
.plugin(AccountManagementPlugin::new())
.plugin(OrganizationPlugin::new())
.build()
.await?,
);
println!("🔐 BetterAuth instance created");
println!("📝 Registered plugins: {:?}", auth.plugin_names());
let app = create_app_router(auth).await;
println!("🌐 Starting server on http://localhost:8080");
println!("📖 Available endpoints:");
println!(" Authentication:");
println!(" POST /auth/sign-up/email - Sign up with email/password");
println!(" POST /auth/sign-in/email - Sign in with email/password");
println!(" POST /auth/sign-in/username - Sign in with username/password");
println!(" Session Management:");
println!(" GET /auth/get-session - Get current session info");
println!(" POST /auth/sign-out - Sign out current session");
println!(" GET /auth/list-sessions - List all user sessions");
println!(" POST /auth/revoke-session - Revoke specific session");
println!(" POST /auth/revoke-sessions - Revoke all user sessions");
println!(" POST /auth/revoke-other-sessions - Revoke all except current");
println!(" Password Management:");
println!(" POST /auth/forget-password - Request password reset");
println!(" POST /auth/reset-password - Reset password with token");
println!(" GET /auth/reset-password/{{token}} - Validate reset token");
println!(" POST /auth/change-password - Change password (auth)");
println!(" POST /auth/set-password - Set password for OAuth users (auth)");
println!(" Email Verification:");
println!(" POST /auth/send-verification-email - Send verification email (auth)");
println!(" GET /auth/verify-email - Verify email with token");
println!(" User Management:");
println!(" POST /auth/update-user - Update user profile (auth)");
println!(" POST /auth/delete-user - Delete user account (auth)");
println!(" POST /auth/change-email - Change email address (auth)");
println!(" GET /auth/delete-user/callback - Confirm deletion via token");
println!(" Account Management:");
println!(" GET /auth/list-accounts - List linked accounts (auth)");
println!(" POST /auth/unlink-account - Unlink an account (auth)");
println!(" Organization:");
println!(" POST /auth/organization/create - Create organization (auth)");
println!(" POST /auth/organization/update - Update organization (auth)");
println!(" POST /auth/organization/delete - Delete organization (auth)");
println!(" GET /auth/organization/list - List organizations (auth)");
println!(" GET /auth/organization/get-full-organization - Get full org (auth)");
println!(" POST /auth/organization/set-active - Set active org (auth)");
println!(" POST /auth/organization/leave - Leave organization (auth)");
println!(" POST /auth/organization/check-slug - Check slug availability (auth)");
println!(" Organization Members:");
println!(" GET /auth/organization/get-active-member - Get active member (auth)");
println!(" GET /auth/organization/list-members - List members (auth)");
println!(" POST /auth/organization/remove-member - Remove member (auth)");
println!(" POST /auth/organization/update-member-role - Update role (auth)");
println!(" Organization Invitations:");
println!(" POST /auth/organization/invite-member - Invite member (auth)");
println!(" GET /auth/organization/get-invitation - Get invitation (auth)");
println!(" GET /auth/organization/list-invitations - List invitations (auth)");
println!(" POST /auth/organization/accept-invitation - Accept invitation (auth)");
println!(" POST /auth/organization/reject-invitation - Reject invitation (auth)");
println!(" POST /auth/organization/cancel-invitation - Cancel invitation (auth)");
println!(" POST /auth/organization/has-permission - Check permission (auth)");
println!(" Other:");
println!(" GET /auth/ok - Health check");
println!(" GET /api/profile - Protected API route");
println!(" GET /api/public - Public API route");
let listener = TcpListener::bind("0.0.0.0:8080").await?;
axum::serve(listener, app).await?;
Ok(())
}
async fn create_app_router(auth: Arc<BetterAuth<MemoryDatabaseAdapter>>) -> Router {
let auth_router = auth.clone().axum_router();
Router::new()
.route("/api/profile", get(get_user_profile))
.route("/api/protected", get(protected_route))
.route("/api/public", get(public_route))
.nest("/auth", auth_router)
.layer(CorsLayer::permissive())
.with_state(auth)
}
async fn get_user_profile(session: CurrentSession<MemoryDatabaseAdapter>) -> impl IntoResponse {
Json(serde_json::json!({
"id": session.user.id(),
"email": session.user.email(),
"name": session.user.name(),
"created_at": session.user.created_at().to_rfc3339(),
}))
}
async fn protected_route(session: CurrentSession<MemoryDatabaseAdapter>) -> impl IntoResponse {
Json(serde_json::json!({
"message": "This is a protected route",
"user_id": session.user.id(),
}))
}
async fn public_route(session: OptionalSession<MemoryDatabaseAdapter>) -> impl IntoResponse {
let user_info = session.0.map(|s| {
serde_json::json!({
"id": s.user.id(),
"email": s.user.email(),
})
});
Json(serde_json::json!({
"message": "This is a public route",
"user": user_info,
}))
}