Metadata-Version: 2.4
Name: vexen-auth
Version: 0.1.2
Summary: Authentication system with hexagonal architecture
Author-email: albakore <kevink.contacto@gmail.com>
License: MIT
Requires-Python: >=3.11
Requires-Dist: asyncpg>=0.29.0
Requires-Dist: bcrypt>=4.1.0
Requires-Dist: greenlet>=3.0.0
Requires-Dist: pyjwt>=2.8.0
Requires-Dist: redis[hiredis]>=5.0.0
Requires-Dist: sqlalchemy[asyncio]>=2.0.44
Provides-Extra: dev
Requires-Dist: mypy>=1.8.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
Requires-Dist: pytest>=9.0.1; extra == 'dev'
Requires-Dist: ruff>=0.14.7; extra == 'dev'
Provides-Extra: redis
Requires-Dist: redis[hiredis]>=5.0.0; extra == 'redis'
Description-Content-Type: text/markdown

# vexen-auth

Sistema de autenticación para aplicaciones Vexen con arquitectura hexagonal.

## Características

- **JWT Authentication**: Tokens de acceso y refresh
- **Provider Local**: Autenticación email/password
- **Sistema Extensible**: Listo para OAuth, SAML, etc.
- **Password Hashing**: Bcrypt con salt automático
- **Token Management**: Manejo y revocación de tokens
- **SQLAlchemy Async**: Integración con SQLAlchemy 2.0+
- **Arquitectura Hexagonal**: Separación clara de capas
- **Type Safe**: Totalmente tipado
- **Integración**: Compatible con vexen-user y vexen-rbac

## Instalación

```bash
pip install vexen-auth
```

## Uso Rápido

```python
import asyncio
from vexen_auth import VexenAuth, AuthConfig, LoginRequest

async def main():
    # Configurar VexenAuth
    config = AuthConfig(
        database_url="postgresql+asyncpg://user:pass@localhost/db",
        secret_key="your-secret-key",
        access_token_expires_minutes=15,
        refresh_token_expires_days=30,
    )

    # Usar VexenAuth
    async with VexenAuth(config) as auth:
        # Login
        login_req = LoginRequest(
            email="user@example.com",
            password="SecurePassword123"
        )
        response = await auth.service.login(login_req)

        if response:
            print(f"Access token: {response.access_token}")
            print(f"User ID: {response.user_id}")

if __name__ == "__main__":
    asyncio.run(main())
```

## Arquitectura

VexenAuth sigue arquitectura hexagonal con clara separación de responsabilidades:

```
vexen_auth/
├── domain/              # Lógica de negocio y entidades
│   ├── entity/         # Entidades de dominio (AuthToken, UserCredential)
│   ├── repository/     # Puertos de repositorio (interfaces)
│   └── provider/       # Puerto de proveedor de auth (interface)
│
├── application/        # Casos de uso y DTOs
│   ├── dto/           # Data Transfer Objects
│   ├── usecase/       # Casos de uso (Login, Refresh, Logout, Verify)
│   └── service/       # Servicio de aplicación
│
└── infraestructure/   # Implementaciones externas
    ├── provider/      # Implementaciones de proveedores (Local, OAuth, etc.)
    ├── security/      # Utilidades JWT y password
    └── output/
        └── persistence/
            └── sqlalchemy/  # Adaptador SQLAlchemy
```

## Configuración

### Opciones de AuthConfig

```python
@dataclass
class AuthConfig:
    # Base de datos
    database_url: str                      # URL de conexión PostgreSQL
    adapter: str = "sqlalchemy"            # Adaptador de persistencia

    # Configuración JWT
    secret_key: str                        # Clave de firma JWT
    algorithm: str = "HS256"               # Algoritmo JWT
    access_token_expires_minutes: int = 15 # TTL del access token
    refresh_token_expires_days: int = 30   # TTL del refresh token

    # Integración externa (opcional)
    user_service = None                    # Instancia VexenUser
    user_repository = None                 # Repositorio de usuarios directo
```

## API Reference

### Servicio de Autenticación

#### Login

```python
from vexen_auth import LoginRequest

request = LoginRequest(
    email="user@example.com",
    password="password123"
)

response = await auth.service.login(request)
# Retorna: LoginResponse | None
# Response contiene: access_token, refresh_token, user_id
```

#### Refresh Token

```python
from vexen_auth import RefreshTokenRequest

request = RefreshTokenRequest(
    refresh_token="..."
)

response = await auth.service.refresh(request)
# Retorna: RefreshTokenResponse | None
# Response contiene: access_token
```

#### Logout

```python
from vexen_auth import LogoutRequest

request = LogoutRequest(
    refresh_token="..."
)

success = await auth.service.logout(request)
# Retorna: bool
```

#### Verificar Token

```python
from vexen_auth import VerifyTokenRequest

request = VerifyTokenRequest(
    access_token="..."
)

response = await auth.service.verify(request)
# Retorna: VerifyTokenResponse | None
# Response contiene: valid, user_id
```

## Integración con vexen-user

VexenAuth necesita información de usuarios de vexen-user. Puedes integrarlo de dos formas:

### Opción 1: Acceso Directo a Repositorio

```python
from vexen_user import VexenUser

# Inicializar vexen-user
user_system = VexenUser(database_url="postgresql+asyncpg://...")
await user_system.init()

# Configurar VexenAuth con repositorio de usuarios
config = AuthConfig(
    database_url="postgresql+asyncpg://...",
    secret_key="...",
    user_repository=user_system.repository,
)

auth = VexenAuth(config)
await auth.init()
```

### Opción 2: Usando vexen-core

```python
from vexen_core import VexenContainer, VexenConfig

config = VexenConfig(
    database_url="postgresql+asyncpg://...",
    secret_key="...",
)

async with VexenContainer(config) as vexen:
    # Auth ya está integrado con user
    response = await vexen.auth.service.login(request)
```

## Schema de Base de Datos

VexenAuth crea dos tablas:

### user_credentials
- `id` (int, PK)
- `user_id` (str, unique, FK a tabla users)
- `password_hash` (str)
- `created_at` (datetime)
- `updated_at` (datetime, nullable)

### auth_tokens
- `id` (int, PK)
- `user_id` (str, FK a tabla users)
- `token` (str, unique, refresh token hasheado)
- `expires_at` (datetime)
- `created_at` (datetime)
- `revoked` (bool)

## Consideraciones de Seguridad

1. **Password Hashing**: Usa bcrypt con salting automático
2. **Token Storage**: Refresh tokens se hashean (SHA-256) antes de almacenar
3. **Token Expiration**: Expiración configurable para access y refresh tokens
4. **Token Revocation**: Logout explícito revoca refresh tokens
5. **JWT Algorithm**: Por defecto HS256, configurable

## Extender Proveedores de Autenticación

VexenAuth soporta múltiples proveedores de autenticación. Para agregar un nuevo proveedor:

```python
from vexen_auth.domain.provider import IAuthProviderPort

class OAuthProvider(IAuthProviderPort):
    async def authenticate(self, email: str, password: str):
        # Implementar autenticación OAuth
        pass

    async def refresh_token(self, refresh_token: str):
        # Implementar refresh de token
        pass

    # Implementar otros métodos requeridos...
```

## Desarrollo

```bash
# Instalar dependencias
pip install -e ".[dev]"

# Ejecutar ejemplo
python example_usage.py

# Formatear código
ruff format .

# Linting
ruff check . --fix
```

## Licencia

MIT

## Proyectos Relacionados

- [vexen-user](https://github.com/vexen-labs/vexen-user) - Sistema de gestión de usuarios
- [vexen-rbac](https://github.com/vexen-labs/vexen-rbac) - Sistema de control de acceso basado en roles
- [vexen-core](https://github.com/vexen-labs/vexen-core) - Capa de integración
