A simple, reusable authentication crate supporting both Rocket backend API and Yew frontend authentication components with multi-user support.
https://crates.io/crates/prisma_auth
example | ||
src | ||
tests | ||
.gitignore | ||
Cargo.lock | ||
Cargo.toml | ||
LICENSE | ||
README.md | ||
test.sh |
Prisma Auth
A simple, reusable authentication crate supporting both Rocket backend API and Yew frontend authentication components with multi-user support.
Features
- Backend Support: Rocket-based authentication with JWT tokens
- Multi-User Authentication: Support for multiple users with roles and permissions
- Secure Password Hashing: Uses Argon2 for password hashing
- Role-Based Access Control: Dynamic roles and permissions system
- Frontend Support: Yew components for login and authentication guards
- Token Management: Automatic token storage, validation, and expiration
- Modular Design: Use backend, frontend, or both features as needed
Usage
Add to your Cargo.toml
:
[dependencies]
# For backend (Rocket API)
prisma_auth = { version = "0.2.1", features = ["rocket_backend"] }
# For frontend (Yew WASM)
prisma_auth = { version = "0.2.1", features = ["yew_frontend"] }
# For both
prisma_auth = { version = "0.2.1", features = ["rocket_backend", "yew_frontend"] }
Backend Usage (Rocket)
Basic Setup
use rocket::State;
use prisma_auth::multi_user::{AuthService, MultiUserTokenStore, MultiUserAuthGuard, multi_user_login_handler, register_handler};
use prisma_auth::storage::InMemoryStorage;
use prisma_auth::{LoginRequest, RegisterRequest, TokenResponse};
#[rocket::post("/login", format = "json", data = "<body>")]
pub fn login(
body: Json<LoginRequest>,
token_store: &State<MultiUserTokenStore>,
auth_service: &State<AuthService<InMemoryStorage>>,
) -> Result<Json<TokenResponse>, Status> {
multi_user_login_handler(body, token_store, auth_service)
}
#[rocket::post("/register", format = "json", data = "<body>")]
pub fn register(
body: Json<RegisterRequest>,
auth_service: &State<AuthService<InMemoryStorage>>,
admin: MultiUserAuthGuard,
) -> Result<Json<User>, Status> {
register_handler(body, auth_service, admin)
}
#[rocket::get("/protected")]
pub fn protected_route(auth: MultiUserAuthGuard) -> String {
format!("Hello, {}! Your role: {}", auth.username, auth.role)
}
#[rocket::get("/admin-only")]
pub fn admin_only(auth: MultiUserAuthGuard) -> Result<&'static str, Status> {
if auth.has_permission("admin") || auth.is_admin() {
Ok("Admin area accessed!")
} else {
Err(Status::Forbidden)
}
}
#[launch]
fn rocket() -> _ {
let storage = InMemoryStorage::new().with_default_roles();
let auth_service = AuthService::new(storage);
rocket::build()
.manage(MultiUserTokenStore::new())
.manage(auth_service)
.mount("/api", routes![login, register, protected_route, admin_only])
}
Environment Variables
ADMIN_PASSWORD
: Required. The initial admin password for authenticationTOKEN_TTL_SECONDS
: Optional. Token expiration time in seconds (default: 600)
Frontend Usage (Yew)
Login Component
use yew::prelude::*;
use prisma_auth::frontend::{MultiUserLoginComponent, UserInfo};
#[function_component(Login)]
pub fn login() -> Html {
let on_success = Callback::from(|user_info: UserInfo| {
web_sys::console::log_1(&format!("Login successful! User: {}, Role: {}",
user_info.username, user_info.role).into());
});
html! {
<MultiUserLoginComponent
api_base_url={"http://localhost:8000/api".to_string()}
on_success={on_success}
title={"My App".to_string()}
subtitle={"Please login".to_string()}
show_username={true} // Enable multi-user mode
/>
}
}
Basic Authentication Guard
use yew::prelude::*;
use prisma_auth::frontend::AuthGuardComponent;
#[function_component(ProtectedPage)]
pub fn protected_page() -> Html {
let fallback = html! {
<div>{"Please login to access this page"}</div>
};
html! {
<AuthGuardComponent fallback={Some(fallback)}>
<div>{"This content is only visible to authenticated users"}</div>
</AuthGuardComponent>
}
}
Permission-Based Guards
use yew::prelude::*;
use prisma_auth::frontend::{PermissionGuardComponent, use_multi_user_auth};
#[function_component(AdminPage)]
pub fn admin_page() -> Html {
let (user_info, _refresh) = use_multi_user_auth();
html! {
<PermissionGuardComponent required_permission="admin_panel".to_string()>
<div>
<h1>{"Admin Panel"}</h1>
{ if let Some(user) = user_info {
html! { <p>{format!("Welcome, {}!", user.username)}</p> }
} else {
html! { <p>{"Loading user info..."}</p> }
}}
</div>
</PermissionGuardComponent>
}
}
Manual Token Management
use prisma_auth::frontend::{get_stored_token, store_token, logout, is_authenticated};
if is_authenticated() {
// User has a valid token stored
}
// Get the current token
if let Some(token) = get_stored_token() {
// Use token for API requests
}
store_token("your-jwt-token").unwrap();
// Logout (remove stored token)
logout().unwrap();
Making Authenticated API Requests
use prisma_auth::frontend::{make_authenticated_request, make_request_with_token};
// Using stored token automatically
let response = make_authenticated_request(
"GET",
"/protected-endpoint",
None,
"http://localhost:8000/api"
).await?;
// Using a specific token
let response = make_request_with_token(
"POST",
"/endpoint",
Some(serde_json::json!({"data": "value"})),
Some("your-token"),
"http://localhost:8000/api"
).await?;
User Management
use prisma_auth::frontend::{get_user_info, logout_multi_user, use_multi_user_auth};
#[function_component(UserProfile)]
pub fn user_profile() -> Html {
let (user_info, refresh) = use_multi_user_auth();
let logout_click = {
let refresh = refresh.clone();
Callback::from(move |_| {
let _ = logout_multi_user();
refresh.emit(());
})
};
html! {
<div>
{ if let Some(user) = user_info {
html! {
<div>
<h2>{"User Profile"}</h2>
<p>{format!("Username: {}", user.username)}</p>
<p>{format!("Role: {}", user.role)}</p>
<button onclick={logout_click}>{"Logout"}</button>
</div>
}
} else {
html! { <p>{"Not logged in"}</p> }
}}
</div>
}
}
Role and Permission Management
Creating Custom Roles
use prisma_auth::{Role, storage::InMemoryStorage, multi_user::AuthService};
let storage = InMemoryStorage::new();
let auth_service = AuthService::new(storage);
// Create custom roles
let editor_role = Role {
name: "editor".to_string(),
permissions: vec!["read".to_string(), "write".to_string(), "edit_posts".to_string()],
description: Some("Can read, write, and edit posts".to_string()),
};
let moderator_role = Role {
name: "moderator".to_string(),
permissions: vec!["read".to_string(), "moderate_comments".to_string(), "ban_users".to_string()],
description: Some("Can moderate content and manage users".to_string()),
};
auth_service.manage_role(editor_role)?;
auth_service.manage_role(moderator_role)?;
User Registration with Roles
use prisma_auth::RegisterRequest;
let register_request = RegisterRequest {
username: "alice".to_string(),
password: "secure_password123".to_string(),
role: Some("editor".to_string()),
};
let user = auth_service.register_user(register_request)?;
Contributing
Contributions are welcome! Please fork the repository, make your changes, and open a pull request.
- Fork the Project on Forgejo
- Create your Feature Branch (
git checkout -b feature/AmazingFeature
) - Commit your Changes (
git commit -m 'Add some AmazingFeature'
) - Push to the Branch (
git push origin feature/AmazingFeature
) - Open a Pull Request
License
Distributed under the European Union Public License v1.2. See LICENSE
for more information.
Contact
Aitor Astorga Saez de Vicuña - a.astorga.sdv@protonmail.com
Project Link: https://git.prisma.moe/aichan/prisma_auth
Acknowledgments
Thanks to these amazing projects and technologies!
- Rust Yew - A modern Rust framework for creating multi-threaded front-end web apps with WebAssembly
- Rocket - A web framework for Rust that makes it simple to write fast, secure web applications
- WebAssembly - A binary instruction format for a stack-based virtual machine