prisma_auth 0.2.1

A simple authentication crate supporting both Rocket backend API and Yew frontend authentication components
Documentation
<h1 id="readme-top">Prisma Auth</h1>

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

<p align="right">(<a href="#readme-top">back to top</a>)</p>

## Usage

Add to your `Cargo.toml`:

```toml
[dependencies]
# For backend (Rocket API)
prisma_auth = { version = "0.2.0", features = ["rocket_backend"] }

# For frontend (Yew WASM)
prisma_auth = { version = "0.2.0", features = ["yew_frontend"] }

# For both
prisma_auth = { version = "0.2.0", features = ["rocket_backend", "yew_frontend"] }
```

<p align="right">(<a href="#readme-top">back to top</a>)</p>

## Backend Usage (Rocket)

### Basic Setup

```rust
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 authentication
- `TOKEN_TTL_SECONDS`: Optional. Token expiration time in seconds (default: 600)

<p align="right">(<a href="#readme-top">back to top</a>)</p>

## Frontend Usage (Yew)

### Login Component

```rust
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

```rust
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

```rust
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

```rust
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

```rust
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

```rust
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>
    }
}
```

<p align="right">(<a href="#readme-top">back to top</a>)</p>

## Role and Permission Management

### Creating Custom Roles

```rust
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

```rust
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)?;
```

<p align="right">(<a href="#readme-top">back to top</a>)</p>

## Contributing

Contributions are welcome! Please fork the repository, make your changes, and open a pull request.

1. Fork the Project on [Forgejo]https://git.prisma.moe/aichan/prisma_auth
2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
4. Push to the Branch (`git push origin feature/AmazingFeature`)
5. Open a Pull Request

<p align="right">(<a href="#readme-top">back to top</a>)</p>

## License

Distributed under the European Union Public License v1.2. See `LICENSE` for more information.

<p align="right">(<a href="#readme-top">back to top</a>)</p>

## Contact

Aitor Astorga Saez de Vicuña - a.astorga.sdv@protonmail.com

Project Link: [https://git.prisma.moe/aichan/prisma_auth](https://git.prisma.moe/aichan/prisma_auth)

<p align="right">(<a href="#readme-top">back to top</a>)</p>

## Acknowledgments

Thanks to these amazing projects and technologies!

- [Rust Yew]https://yew.rs/ - A modern Rust framework for creating multi-threaded front-end web apps with WebAssembly
- [Rocket]https://rocket.rs/ - A web framework for Rust that makes it simple to write fast, secure web applications
- [WebAssembly]https://webassembly.org/ - A binary instruction format for a stack-based virtual machine

<p align="right">(<a href="#readme-top">back to top</a>)</p>