Auth Plugin API Reference

Authentication and authorization plugin for Structum Lab.

Structum Auth (structum-auth)

Documentation Python 3.11+ License: Apache-2.0

Structum Auth è il plugin ufficiale per la gestione dell’autenticazione JWT, l’hashing sicuro delle password (Argon2) e il controllo degli accessi (RBAC).

🚀 Installazione

pip install structum-auth

📚 Documentazione Completa

Documentazione, API Reference e Guide: 👉 https://structum-lab.pages.dev/plugins/auth

✨ Funzionalità Principali

  • JWT Management: Creazione e validazione token sicura.

  • Argon2 Hashing: Standard di sicurezza per lo storage delle password.

  • RBAC: Controllo accessi basato sui ruoli.

  • Integrazione FastAPI: Dipendenze pronte all’uso per proteggere le route.

Auth Plugin Package

Authentication plugin for Structum Lab.

class structum_lab.plugins.auth.AuthInterface(*args, **kwargs)[source]

Bases: Protocol

Protocol for authentication providers in Structum Lab.

This is the main entry point for all authentication operations. Implementations provide JWT-based authentication, password hashing, and token management.

The auth system is storage-agnostic - it doesn’t manage users directly. Instead, it uses UserRepositoryInterface to fetch user data, keeping authentication logic decoupled from storage.

Implementations:

Example

See usage in specific implementations like JWTAuthProvider.

__init__(*args, **kwargs)
authenticate(username: str, password: str, user_repo: UserRepositoryInterface) TokenPair | None[source]

Authenticate a user.

hash_password(password: str) str[source]

Hash a password.

refresh(refresh_token: str, user_repo: UserRepositoryInterface) TokenPair | None[source]

Refresh access token.

verify_access_token(token: str) dict[str, Any] | None[source]

Verify an access token.

verify_password(password: str, hashed: str) bool[source]

Verify a password.

class structum_lab.plugins.auth.PasswordHasherInterface(*args, **kwargs)[source]

Bases: Protocol

Protocol for secure password hashing in Structum Lab.

Implementations must use cryptographically secure hashing algorithms (e.g., Argon2, b

crypt, scrypt). Never use fast hashes like MD5 or SHA-1

for passwords.

Implementations:
  • Argon2Hasher (recommended)

  • BcryptHasher

Example:

Using password hasher:

from structum_lab.plugins.auth.password import Argon2Hasher

hasher = Argon2Hasher()

# Hash password during registration
hashed = hasher.hash("user_password_123")
# Store hashed in database: user.hashed_password = hashed

# Verify during login
if hasher.verify("user_password_123", hashed):
    # Password matches
    return create_token(user)
else:
    # Invalid password
    raise AuthenticationError("Invalid credentials")
Warning:

Never log, display, or store plain-text passwords. Always hash passwords immediately upon receipt.

See Also:

AuthInterface: Auth provider using password hasher UserInterface: User entity with hashed_password property

__init__(*args, **kwargs)
hash(password: str) str[source]

Hash a plain-text password securely.

Parameters:
password : str

Plain-text password to hash. No length restrictions, but implementations may truncate very long passwords.

Returns:

Hashed password string including algorithm identifier and salt.

Format is implementation-specific (e.g., Argon2: $argon2id$v=19$...).

Return type:

str

Example

Creating user with hashed password:

# During user registration
plain_password = request.form["password"]
hashed = auth.hash_password(plain_password)

user = User(
    id=generate_id(),
    username=request.form["username"],
    hashed_password=hashed,  # Store this
    roles=["user"]
)
user_repo.save(user)

Warning

Hashing is intentionally slow (100-500ms) to resist brute-force attacks. Do not hash passwords in tight loops or performance-critical paths.

Note

Each call generates a unique hash (due to random salt) even for the same password. This is expected and secure behavior.

verify(password: str, hashed: str) bool[source]

Verify a plain-text password against a hash.

Parameters:
password : str

Plain-text password to verify.

hashed : str

Previously hashed password (from database).

Returns:

True if password matches hash, False otherwise.

Return type:

bool

Example

Password verification during login:

# Get user from database
user = user_repo.find_by_username(username)
if not user:
    return None  # User not found

# Verify password
if auth.verify_password(password, user.hashed_password):
    # Authentication successful
    return auth.create_tokens(user)
else:
    # Invalid password
    log.warning("Failed login attempt", username=username)
    return None

Warning

Always use constant-time comparison internally to prevent timing attacks. Most modern hashing libraries handle this automatically.

Note

Returns False for invalid/malformed hashes rather than raising exceptions. This prevents information leakage about hash format.

class structum_lab.plugins.auth.TokenPair(access_token: str, refresh_token: str, token_type: str = 'bearer', expires_at: datetime | None = None)[source]

Bases: object

Data class containing JWT access and refresh token pair.

access_token

Short-lived JWT access token for API requests.

Type:

str

refresh_token

Long-lived token for obtaining new access tokens.

Type:

str

token_type

Token type, typically “bearer” for JWT. Defaults to “bearer”.

Type:

str

expires_at

Expiration timestamp for access token, if available.

Type:

datetime | None

Example

Creating and using token pair:

tokens = TokenPair(
    access_token="eyJ0eXAiOiJKV1QiLCJhbGc...",
    refresh_token="eyJ0eXAiOiJKV1QiLCJhbGc...",
    token_type="bearer",
    expires_at=datetime.now() + timedelta(hours=1)
)

# Use in HTTP Authorization header
headers = {"Authorization": f"{tokens.token_type} {tokens.access_token}"}

Note

This class is frozen (immutable) to prevent accidental token modification. Tokens should be treated as opaque strings and never parsed by clients.

See also

AuthInterface.authenticate(): Method that returns token pairs AuthInterface.refresh(): Refresh access tokens

__init__(access_token: str, refresh_token: str, token_type: str = 'bearer', expires_at: datetime | None = None)
expires_at : datetime | None = None
token_type : str = 'bearer'
access_token : str
refresh_token : str
class structum_lab.plugins.auth.UserInterface(*args, **kwargs)[source]

Bases: Protocol

Protocol for authenticated user entities in Structum Lab.

Applications must implement this protocol for their User model to integrate with the authentication system. The auth system never creates or modifies users - it only queries them via UserRepositoryInterface.

Example

Implementing UserInterface:

from dataclasses import dataclass

@dataclass
class User:
    id: str
    username: str
    hashed_password: str
    roles: list[str]
    permissions: set[str]

    def has_permission(self, permission: str) -> bool:
        # Check role-based permissions
        for role in self.roles:
            if permission in ROLE_PERMISSIONS.get(role, set()):
                return True
        # Check user-specific permissions
        return permission in self.permissions

Using with auth:

user = user_repo.find_by_username("john")
if user and user.has_permission("users:write"):
    # Allow operation
    pass

Note

This is a Protocol, not a base class. Your User model doesn’t need to inherit from this - just implement the required properties and methods.

See also

UserRepositoryInterface: Repository for user data access AuthInterface: Authentication provider using users

__init__(*args, **kwargs)
has_permission(permission: str) bool[source]

Check if user has a specific permission.

Parameters:
permission : str

Permission string, typically in format resource:action (e.g., “users:write”, “posts:delete”).

Returns:

True if user has the permission, False otherwise.

Return type:

bool

Example

Permission-based authorization:

@app.delete("/users/{user_id}")
async def delete_user(user_id: str, current_user: User = Depends(get_current_user)):
    if not current_user.has_permission("users:delete"):
        raise HTTPException(403, "Permission denied")
    # Delete user

Role-based permission mapping:

ROLE_PERMISSIONS = {
    "admin": {"users:read", "users:write", "users:delete"},
    "user": {"users:read"},
}

def has_permission(self, permission: str) -> bool:
    return any(
        permission in ROLE_PERMISSIONS.get(role, set())
        for role in self.roles
    )

Note

Permission format is application-defined. Use a consistent naming scheme (e.g., resource:action).

property hashed_password : str

User’s hashed password.

Returns:

Securely hashed password (e.g., Argon2, bcrypt).

Return type:

str

Warning

Never store or transmit plain-text passwords. This property should only return hashed values.

Example

Password verification:

if auth.verify_password(input_password, user.hashed_password):
    # Password matches
    pass

See also

PasswordHasherInterface.hash(): Hash passwords PasswordHasherInterface.verify(): Verify passwords

property id : str

Unique identifier for the user.

Returns:

User ID, typically a UUID or database primary key.

Return type:

str

Example

User ID in token payload:

token_payload = {"user_id": user.id, "exp": ...}
property roles : list[str]

List of roles assigned to the user.

Returns:

Role names (e.g., [“admin”, “user”, “moderator”]).

Return type:

list[str]

Example

Role-based access control:

if "admin" in user.roles:
    # Allow admin operation
    pass

Note

Roles should be lowercase strings. Use has_permission() for fine-grained permission checks.

property username : str

User’s username or email address.

Returns:

Username, typically used for login and display.

Return type:

str

Example

username in login:

user = user_repo.find_by_username(username)
if user and auth.verify_password(password, user.hashed_password):
    return auth.authenticate(...)
class structum_lab.plugins.auth.JWTAuthProvider(secret_key: str, refresh_secret_key: str | None = None, algorithm: str = 'HS256', access_token_expire_minutes: int = 15, refresh_token_expire_days: int = 7)[source]

Bases: BaseAuthProvider, AuthInterface

JWT-based authentication provider.

Manages: - User authentication (verifying password) - Token generation (Access + Refresh) - Token verification - Password hashing (via Argon2)

Example

>>> auth = JWTAuthProvider.from_config()
>>> tokens = auth.authenticate("user", "pass", user_repo)
__init__(secret_key: str, refresh_secret_key: str | None = None, algorithm: str = 'HS256', access_token_expire_minutes: int = 15, refresh_token_expire_days: int = 7)[source]

Initialize JWT provider.

Parameters:
secret_key: str

Secret for signing access tokens

refresh_secret_key: str | None = None

Secret for refresh tokens (defaults to secret_key)

algorithm: str = 'HS256'

Signing algorithm (HS256, RS256, etc.)

access_token_expire_minutes: int = 15

Access token TTL

refresh_token_expire_days: int = 7

Refresh token TTL

authenticate(username: str, password: str, user_repo: UserRepositoryInterface) TokenPair | None[source]

Authenticate user and return tokens.

classmethod from_config(config_key: str | None = None, *, config: ConfigInterface | None = None) JWTAuthProvider[source]

Factory method to create provider from config.

hash_password(password: str) str[source]

Hash password using Argon2.

refresh(refresh_token: str, user_repo: UserRepositoryInterface) TokenPair | None[source]

Refresh tokens using refresh token.

verify_access_token(token: str) dict[str, Any] | None[source]

Verify access token and return payload.

verify_password(password: str, hashed: str) bool[source]

Verify password against hash.

class structum_lab.plugins.auth.Argon2PasswordHasher(time_cost: int = 2, memory_cost: int = 65536, parallelism: int = 1, hash_len: int = 32, salt_len: int = 16)[source]

Bases: PasswordHasherInterface

Argon2 implementation of PasswordHasherInterface.

__init__(time_cost: int = 2, memory_cost: int = 65536, parallelism: int = 1, hash_len: int = 32, salt_len: int = 16)[source]
hash(password: str) str[source]

Hash a password.

verify(password: str, hashed: str) bool[source]

Verify password against hash.

class structum_lab.plugins.auth.RoleChecker[source]

Bases: object

Helper for checking roles and permissions.

static check_permission(user: UserInterface, permission: str) bool[source]

Check permission (delegates to user object).

static has_any_role(user: UserInterface, roles: list[str]) bool[source]

Check if user has any of the specified roles.

static has_role(user: UserInterface, role: str) bool[source]

Check if user has specific role.

Base Authentication

Base class for auth implementations with Factory Pattern support.

class structum_lab.plugins.auth.base.BaseAuthProvider[source]

Bases: object

Base class providing Factory Pattern configuration.

DEFAULT_CONFIG_KEY : ClassVar[str] = 'auth'

Default config key prefix

classmethod get_config(config_key: str | None = None, config: ConfigInterface | None = None) tuple[dict[str, Any], dict[str, Any]][source]

Helper to get config and secrets.

Returns:

Tuple of (public_config, secrets)

JWT Authentication

JWT Authentication Provider.

Implements AuthInterface using JSON Web Tokens (access + refresh).

class structum_lab.plugins.auth.jwt.JWTAuthProvider(secret_key: str, refresh_secret_key: str | None = None, algorithm: str = 'HS256', access_token_expire_minutes: int = 15, refresh_token_expire_days: int = 7)[source]

Bases: BaseAuthProvider, AuthInterface

JWT-based authentication provider.

Manages: - User authentication (verifying password) - Token generation (Access + Refresh) - Token verification - Password hashing (via Argon2)

Example

>>> auth = JWTAuthProvider.from_config()
>>> tokens = auth.authenticate("user", "pass", user_repo)
__init__(secret_key: str, refresh_secret_key: str | None = None, algorithm: str = 'HS256', access_token_expire_minutes: int = 15, refresh_token_expire_days: int = 7)[source]

Initialize JWT provider.

Parameters:
secret_key: str

Secret for signing access tokens

refresh_secret_key: str | None = None

Secret for refresh tokens (defaults to secret_key)

algorithm: str = 'HS256'

Signing algorithm (HS256, RS256, etc.)

access_token_expire_minutes: int = 15

Access token TTL

refresh_token_expire_days: int = 7

Refresh token TTL

classmethod from_config(config_key: str | None = None, *, config: ConfigInterface | None = None) JWTAuthProvider[source]

Factory method to create provider from config.

authenticate(username: str, password: str, user_repo: UserRepositoryInterface) TokenPair | None[source]

Authenticate user and return tokens.

refresh(refresh_token: str, user_repo: UserRepositoryInterface) TokenPair | None[source]

Refresh tokens using refresh token.

verify_access_token(token: str) dict[str, Any] | None[source]

Verify access token and return payload.

hash_password(password: str) str[source]

Hash password using Argon2.

verify_password(password: str, hashed: str) bool[source]

Verify password against hash.

OAuth Support

OAuth2 interface stub for future implementation.

class structum_lab.plugins.auth.oauth.OAuthProvider(*args, **kwargs)[source]

Bases: Protocol

Protocol for OAuth2 providers (Google, GitHub, etc.).

get_login_url(redirect_uri: str) str[source]
exchange_code(code: str) dict[source]
__init__(*args, **kwargs)

Password Hashing

Password hashing using Argon2 (argon2-cffi).

class structum_lab.plugins.auth.password.Argon2PasswordHasher(time_cost: int = 2, memory_cost: int = 65536, parallelism: int = 1, hash_len: int = 32, salt_len: int = 16)[source]

Bases: PasswordHasherInterface

Argon2 implementation of PasswordHasherInterface.

__init__(time_cost: int = 2, memory_cost: int = 65536, parallelism: int = 1, hash_len: int = 32, salt_len: int = 16)[source]
hash(password: str) str[source]

Hash a password.

verify(password: str, hashed: str) bool[source]

Verify password against hash.

Role-Based Access Control (RBAC)

RBAC utilities for permission checking.

class structum_lab.plugins.auth.rbac.RoleChecker[source]

Bases: object

Helper for checking roles and permissions.

static has_role(user: UserInterface, role: str) bool[source]

Check if user has specific role.

static has_any_role(user: UserInterface, roles: list[str]) bool[source]

Check if user has any of the specified roles.

static check_permission(user: UserInterface, permission: str) bool[source]

Check permission (delegates to user object).