fastauth-iq 0.3.4
A comprehensive authentication and authorization library for FastAPI with JWT, cookie support, role-based access control, and automatic database initialization
Requires Python: >=3.9
Keywords: fastapi, authentication, authorization, rbac, role-based, jwt, oauth2, sqlmodel, token, cli, database-initialization

<div align="center">
  <img src="https://raw.githubusercontent.com/hu55ain3laa/fastauth/main/FastAuth.svg" alt="FastAuth Logo" width="350">

  <p>A comprehensive authentication and authorization library for FastAPI applications<br>with JWT-based authentication, role-based authorization, and SQLModel integration.</p>
</div>

<div align="center">
  <a href="https://badge.fury.io/py/fastauth-iq"><img src="https://badge.fury.io/py/fastauth-iq.svg?v=0.3.4" alt="PyPI version"></a>
  <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT"></a>

  <h3>📖 <a href="https://hu55ain3laa.github.io/fastauth/">Full Documentation Available Here</a></h3>
</div>

## Documentation

This README provides a quick overview of FastAuth. For a more complete, interactive documentation with live examples and responsive design, visit our **[GitHub Pages Documentation](https://hu55ain3laa.github.io/fastauth/)**.

## Table of Contents

- [Features](#features)
- [Installation](#installation)
- [Quick Start](#quick-start)
- [Authentication](#authentication)
  - [Login and Token Management](#login-and-token-management)
  - [Protected Routes](#protected-routes)
  - [Cookie-Based Authentication](#cookie-based-authentication)
- [Database Initialization](#database-initialization)
  - [CLI Initialization](#cli-initialization-new-in-v030)
  - [Programmatic Initialization](#programmatic-initialization)
- [Role-Based Authorization](#role-based-authorization)
  - [Standard Roles](#standard-roles)
  - [Role Requirements](#role-requirements)
  - [Role Management API](#role-management-api)
- [API Reference](#api-reference)
  - [Authentication Endpoints](#authentication-endpoints)
  - [Role Management Endpoints](#role-management-endpoints)
- [Error Handling](#error-handling)
  - [Custom Exceptions](#custom-exceptions)
  - [Standardized Error Responses](#standardized-error-responses)
- [Advanced Usage](#advanced-usage)
  - [Custom User Models](#custom-user-models)
  - [Custom Authentication Logic](#custom-authentication-logic)
- [Security Best Practices](#security-best-practices)
- [Project Structure](#project-structure)
- [License](#license)

## Features

- **OAuth2 and JWT authentication** built-in
- **Role-based authorization** system
- **Cookie-based authentication** option
- **Token refresh mechanism** for extended sessions
- **SQLModel integration** for easy database operations
- **CLI utilities** for database initialization and management (new in v0.3.0)
- **Ready-to-use authentication routes** with minimal setup
- **Comprehensive error handling** with standardized error responses (new in v0.3.4)
- **Password hashing** with bcrypt
- **Modular architecture** for better code organization and extensibility

## Installation

```bash
pip install fastauth_iq
```

Or install from source:

```bash
git clone https://github.com/hu55ain3laa/fastauth.git
cd fastauth
pip install -e .
```

## Quick Start

### 1. Create a User Model

FastAuth works with SQLModel's user model. You can use the built-in User model or create your own:

```python
from sqlmodel import SQLModel, Field

class User(SQLModel, table=True):
    id: int = Field(primary_key=True)
    username: str = Field(unique=True)
    email: str = Field(unique=True)
    hashed_password: str
    disabled: bool = Field(default=False)
```

### 2. Initialize FastAuth in Your Application

```python
from fastapi import FastAPI, Depends
from sqlmodel import create_engine, Session, SQLModel

from fastauth import FastAuth, User

# Create FastAPI app
app = FastAPI()

# Setup database
engine = create_engine("sqlite:///./app.db")

# Session dependency
def get_session():
    with Session(engine) as session:
        yield session

# Initialize FastAuth with your configuration
auth = FastAuth(
    secret_key="your-secure-secret-key",  # Use strong secret in production
    algorithm="HS256",
    user_model=User,
    engine=engine,
    use_cookie=True,  # Enable cookie-based auth (optional)
    token_url="/token",
    access_token_expires_in=30,  # minutes
    refresh_token_expires_in=7   # days
)

# Initialize database (choose ONE of these approaches):
# Option 1: Using the CLI tool before starting the application (new in v0.3.0)
#   fastauth app.py                   # Auto-detect settings from your app file
#   # Or use explicit parameters
#   fastauth --db-url="sqlite:///./app.db" --secret-key="your-secret-key"
#
# Option 2: Initializing during application startup
INIT_DB_ON_STARTUP = True  # Set to False to disable

@app.on_event("startup")
def on_startup():
    if INIT_DB_ON_STARTUP:
        auth.initialize_db(
            create_tables=True,         # Create database tables
            init_roles=True,            # Initialize standard roles
            create_admin=True,          # Create superadmin if needed
            admin_username="superadmin", # Default username
            admin_password="admin123"    # Default password
        )

# Add all authentication routes automatically
auth_router = auth.get_auth_router(get_session)
app.include_router(auth_router, tags=["authentication"])

# Add role management routes (new in v0.2.2)
role_router = auth.get_role_router()
app.include_router(role_router, tags=["roles"])

# Set up standardized error handling (new in v0.3.4)
auth.setup_exception_handlers(app)
```

### 3. Protect Your Routes

```python
# Require authentication only
@app.get("/protected")
def protected_route(current_user = Depends(auth.get_current_active_user_dependency())):
    return {"message": f"Hello, {current_user.username}!"}

# Require specific roles (any of the listed roles)
@app.get("/admin-or-moderator")
def admin_or_mod_route(current_user = Depends(auth.require_roles(["admin", "moderator"]))):
    return {"message": f"Hello privileged user, {current_user.username}!"}

# Require all listed roles
@app.get("/admin-and-verified")
def admin_and_verified_route(current_user = Depends(auth.require_all_roles(["admin", "verified"]))):
    return {"message": f"Hello admin with verification, {current_user.username}!"}

# Shortcut for admin-only routes
@app.get("/admin-only")
def admin_only_route(current_user = Depends(auth.is_admin())):
    return {"message": f"Hello admin, {current_user.username}!"}
```

## Authentication

### Login and Token Management

FastAuth implements JWT-based authentication with both access tokens and refresh tokens:

- **Access tokens** are short-lived (default: 30 minutes) and used for regular API access
- **Refresh tokens** are long-lived (default: 7 days) and used to obtain new access tokens

User authentication flow:

1. User submits credentials to `/token` endpoint
2. Server validates credentials and returns access + refresh tokens
3. Client uses access token for API requests (via header or cookie)
4. When access token expires, client uses refresh token to get a new one from `/token/refresh`

### Protected Routes

To protect a route, use FastAuth's dependencies:

```python
# Basic authentication - any valid user
@app.get("/protected")
def protected_route(user = Depends(auth.get_current_active_user_dependency())):
    return {"message": "Protected content", "user": user.username}
```

### Cookie-Based Authentication

FastAuth supports both header-based and cookie-based authentication:

```python
# Enable cookie-based auth when creating FastAuth instance
auth = FastAuth(
    # ... other parameters ...
    use_cookie=True
)
```

With cookie-based auth enabled:
- The `/token` endpoint will set HTTP-only cookies with the tokens
- Protected routes will check for tokens in cookies if not found in headers
- The cookie approach is more secure for browser-based applications

## Database Initialization

### CLI Initialization (new in v0.3.0)

FastAuth provides a convenient CLI tool for database initialization, which is ideal for production environments.

```bash
# Just provide your app file - FastAuth will extract settings automatically
fastauth example.py

# Or use the traditional approach
fastauth --db-url="sqlite:///./app.db" --secret-key="your-secret-key"

# Customize the superadmin credentials
fastauth example.py --username="admin" --password="secure_password"

# Run specific initialization steps
fastauth example.py --init-db --init-roles --create-superadmin
```

The CLI tool will prompt for credentials if not provided, with defaults:
- Username: `superadmin`
- Password: `admin123`

#### Setting up your Application File for Auto-Detection

When using the `fastauth example.py` syntax, FastAuth auto-detects database URL and secret key settings from multiple sources (new in v0.3.3):

**1. Environment Variables:**
```bash
# Set these environment variables before running FastAuth CLI
export DATABASE_URL="sqlite:///./app.db"
export SECRET_KEY="your-secret-key-here"
```

**2. .env Files:**
Create a `.env` file in your project directory:
```
DATABASE_URL=sqlite:///./app.db
SECRET_KEY=your-secret-key-here
```

**3. Python Module Variables:**
```python
# Database URL - any of these formats will be detected
DATABASE_URL = "sqlite:///./app.db"
database_url = "sqlite:///./app.db"
db_url = "sqlite:///./app.db"
engine = create_engine("sqlite:///./app.db")

# Secret Key - any of these formats will be detected
SECRET_KEY = "your-secret-key-here"
secret_key = "your-secret-key-here"
```

**4. Imported Modules and Engine Objects:**
```python
# FastAuth will detect imported engine objects
from database import engine  # Where database.py contains an engine definition

# And imported configuration variables
from config import DATABASE_URL, SECRET_KEY
```

FastAuth will search for these variables in:
- The specified app file
- Common configuration files (config.py, settings.py, db.py, etc.)
- Imported modules

If FastAuth cannot detect your settings, you can still provide them with the `--db-url` and `--secret-key` flags.

### Programmatic Initialization

You can also initialize the database programmatically during application startup, which is simpler for development environments:

```python
# Initialize during application startup
@app.on_event("startup")
def on_startup():
    auth.initialize_db(
        create_tables=True,         # Create database tables
        init_roles=True,            # Initialize standard roles
        create_admin=True,          # Create superadmin if needed
        admin_username="superadmin", # Default username
        admin_password="admin123"    # Default password
    )
```

You can also create a superadmin user programmatically at any time:

```python
# Create a superadmin user with default credentials
auth.create_superadmin()

# Or with custom credentials
auth.create_superadmin(username="admin", password="secure_password")
```

## Role-Based Authorization

FastAuth includes a robust role-based authorization system:

### Standard Roles

The initialization creates these standard roles:
- `superadmin`: Super administrator with all privileges
- `admin`: Administrator with management privileges
- `moderator`: User with content moderation privileges 
- `premium`: Premium tier user
- `verified`: Verified user
- `user`: Standard user with basic privileges

### Role Requirements

FastAuth provides flexible role-based access control:

```python
# Require any of these roles (OR condition)
@app.get("/admin-or-moderator")
def admin_route(user = Depends(auth.require_roles(["admin", "moderator"]))):
    return {"message": "Admin or moderator area"}

# Require all of these roles (AND condition)
@app.get("/premium-and-verified")
def premium_verified_route(user = Depends(auth.require_all_roles(["premium", "verified"]))):
    return {"message": "Premium and verified area"}

# Shortcut for admin-only routes
@app.get("/admin-only")
def admin_only(user = Depends(auth.is_admin())):
    return {"message": "Admin only area"}
```

### Role Management API

FastAuth provides a complete API for role management:

```python
# Get the role router and include it in your app
role_router = auth.get_role_router()
app.include_router(role_router, tags=["roles"])
```

This adds these role management endpoints:
- **POST /roles/** - Create a new role (admin only)
- **GET /roles/** - Get all roles 
- **GET /roles/{role_id}** - Get a role by ID
- **PUT /roles/{role_id}** - Update a role (admin only)
- **DELETE /roles/{role_id}** - Delete a role (admin only)
- **POST /roles/assign/{user_id}/{role_id}** - Assign a role to a user (admin only)
- **DELETE /roles/assign/{user_id}/{role_id}** - Remove a role from a user (admin only)
- **GET /roles/user/{user_id}** - Get all roles for a user

## API Reference

### Authentication Endpoints

FastAuth provides the following authentication endpoints:

- `POST /token` - Login and get access + refresh tokens
- `POST /token/refresh` - Use refresh token to get a new access token
- `POST /users` - Register a new user
- `GET /users/me` - Get current user information

### Role Management Endpoints

FastAuth provides these role management endpoints (all under `/roles` by default):

- `POST /roles/` - Create a new role (admin only)
- `GET /roles/` - Get all roles (authenticated users)
- `GET /roles/{role_id}` - Get a specific role (authenticated users)
- `PUT /roles/{role_id}` - Update a role (admin only)
- `DELETE /roles/{role_id}` - Delete a role (admin only)
- `POST /roles/assign/{user_id}/{role_id}` - Assign role to user (admin only)
- `DELETE /roles/assign/{user_id}/{role_id}` - Remove role from user (admin only)

## Error Handling

FastAuth provides a comprehensive error handling system that delivers consistent, informative error responses across all endpoints (new in v0.3.4).

### Custom Exceptions

The library includes specialized exception classes for different error scenarios:

```python
from fastauth import (
    CredentialsException,    # Authentication failures
    TokenException,          # Token verification issues
    RefreshTokenException,   # Refresh token problems
    InactiveUserException,   # User account is disabled
    UserNotFoundException,   # User doesn't exist
    UserExistsException,     # Username already taken
    RoleNotFoundException,    # Role doesn't exist
    RoleExistsException,     # Role already exists
    PermissionDeniedException # Insufficient permissions
)
```

### Standardized Error Responses

All FastAuth exceptions return a consistent JSON structure:

```json
{
  "error": {
    "code": "FASTAUTH_ERROR_CODE",
    "message": "Human-readable error description",
    "status_code": 401  // HTTP status code
  }
}
```

Enabling error handling is simple:

```python
app = FastAPI()
auth = FastAuth(...)

# Register exception handlers with your FastAPI app
auth.setup_exception_handlers(app)
```

This makes debugging easier and allows clients to handle errors in a consistent way. Each exception type has its own specific error code, making it straightforward to identify and respond to different error scenarios.

## Advanced Usage

### Custom User Models

You can use a custom user model with FastAuth:

```python
class CustomUser(SQLModel, table=True):
    id: int = Field(primary_key=True)
    username: str = Field(unique=True)
    email: str = Field(unique=True)
    hashed_password: str
    disabled: bool = Field(default=False)
    # Additional fields...
    first_name: str = Field(default="")
    last_name: str = Field(default="")

# Pass your custom model to FastAuth
auth = FastAuth(
    # ... other parameters ...
    user_model=CustomUser
)
```

### Custom Authentication Logic

You can customize the authentication logic:

```python
# Custom authentication routes
@app.post("/custom-login")
async def custom_login(
    username: str, 
    password: str, 
    session: Session = Depends(get_session)
):
    user = auth.authenticate_user(username, password)
    if not user:
        raise HTTPException(status_code=401, detail="Invalid credentials")
    
    access_token = auth.create_access_token(data={"sub": user.username})
    return {"access_token": access_token, "token_type": "bearer"}
```

## Security Best Practices

When using FastAuth in your applications, consider these security recommendations:

1. **Deploy your FastAPI app with HTTPS** in production environments
2. **Use a strong secret key** for FastAuth and store it securely (e.g., environment variables)
3. **Configure appropriate token expiration times** based on your security requirements
4. **Keep secure cookie settings** when using cookie-based authentication (FastAuth sets `httpOnly=True` which prevents JavaScript from accessing cookies, protecting against XSS attacks)
5. **Consider implementing rate limiting** on your authentication endpoints to prevent brute force attacks

## Project Structure

FastAuth follows a modular architecture for better maintainability:

```
fastauth/
├── core/           # Core functionality
│   ├── auth.py     # The main FastAuth class
│   ├── password.py # Password management
│   └── tokens.py   # Token generation and validation
├── models/         # Data models
│   ├── user.py     # User models and schemas
│   ├── role.py     # Role models for authorization
│   └── tokens.py   # Token data models
├── routers/        # Route handlers for auth and roles
├── dependencies/   # FastAPI dependencies for auth and roles
└── utils/          # Utility functions and helpers
```

This modular structure makes it easier to:
- Understand the codebase
- Extend or customize functionality
- Test individual components

## License

MIT