ZCore LogoZCore
Core concepts

Security & Authentication Architecture

Explore ZCore's cryptographic services (Argon2id, JWT), the BaseAuth template pipeline, fail-fast production assertions, and scope permissions.

Security in ZCore is not an afterthought; it is integrated directly into the architectural core. The framework provides modern cryptographic primitives, fail-fast production safeguards, and an automated authentication/authorization pipeline.


1. Cryptographic Services (Argon2id & JWT)

Memory-Hard Password Hashing

ZCore uses Argon2id (via argon2-cffi), the winner of the Password Hashing Competition. Unlike legacy algorithms like bcrypt or PBKDF2, Argon2id is memory-hard, providing strong resistance against GPU and ASIC cracking rigs.

ZCore exposes dynamic parameter tuning directly via the Settings class:

  • ARGON2_MEMORY_COST: Memory capacity allocated per hash calculation (Default: 65536 KB / 64 MB).
  • ARGON2_TIME_COST: Number of hashing iterations (Default: 3).
  • ARGON2_PARALLELISM: Parallel processing threads (Default: 4).
from zcore.security import Security

# Generate Argon2id hash
hashed_pwd = Security.hash_password("SuperSecretPassword123")

# Verify plain password against stored hash
is_valid = Security.verify_password("SuperSecretPassword123", hashed_pwd)

JWT Management & Asymmetric Key Support

Security handles JSON Web Token creation, signature verification, and expiration assertions. It supports both symmetric (SECRET_KEY) and enterprise asymmetric key pairs (JWT_PRIVATE_KEY and JWT_PUBLIC_KEY for algorithms like RS256).


2. Fail-Fast Production Secret Assertion

A common deployment disaster in web engineering is deploying an application to production while forgetting to change the default secret key.

ZCore implements an active Fail-Fast Startup Assertion in Security._get_signing_keys():

# Internal fail-fast validation
if is_prod and is_fallback:
    raise RuntimeError(
        "FATAL SECURITY VIOLATION: You are running in PRODUCTION environment "
        "using the insecure default fallback SECRET_KEY. Application startup aborted."
    )

If settings.DEBUG is False (Production) and settings.SECRET_KEY matches the default insecure fallback, the application aborts startup immediately.


3. The BaseAuth[T] Template Pipeline

ZCore does not couple your application to a rigid user table. Instead, BaseAuth[T] is a Generic template class that coordinates token extraction, cryptographic verification, caching, and context binding:

Hit Miss Incoming HTTP Request with Bearer Token 1. Extract token via OAuth2PasswordBearer 2. Security.decode_jwt validates signature & exp 3. Check BaseCache user:identity 4. Validate is_active == True 5. Execute self.fetch_user identity Store in BaseCache TTL from AUTH_CACHE_TTL 6. Bind attributes to ZContext ctx.user_id, restricted_fields Proceed to Route Handler

Dynamic User Cache Lifespan (AUTH_CACHE_TTL)

BaseAuth caches resolved user sessions to eliminate redundant database queries on every authenticated request. The cache expiration time is dynamically resolved from settings.AUTH_CACHE_TTL (default: 300 seconds / 5 minutes) or can be passed explicitly via cache_ttl in the constructor.

Custom Authentication Implementation

UserProtocol models user characteristics flexibly: id is typed as Any, seamlessly supporting auto-incrementing integers, UUIDs, or external strings:

# auth.py
from typing import Any
from pydantic import BaseModel
from zcore import BaseAuth

class AppUser(BaseModel):
    id: Any  # Supports UUID, int, or str
    is_active: bool = True
    is_superuser: bool = False
    scopes: list[str] = []
    all_restricted_fields: list[str] = []

class CustomAuth(BaseAuth[AppUser]):
    # cache_ttl is optional; falls back to settings.AUTH_CACHE_TTL (300s)
    def __init__(self, auto_error: bool = True):
        super().__init__(user_schema=AppUser, cache_prefix="auth", auto_error=auto_error)

    async def fetch_user(self, identity: str) -> AppUser | None:
        # Resolve user from database repository
        db_user = await user_repo.get_by_username(identity)
        return AppUser.model_validate(db_user) if db_user else None

Optional Authentication & Guest Support (auto_error=False)

For endpoints that support both authenticated users and anonymous guests (e.g., public catalogs, guest checkouts):

# main.py
from zcore.security import get_current_user_stub, get_optional_user_stub
from auth import CustomAuth

# Standard strict authentication (raises 401 on missing/invalid token)
strict_auth = CustomAuth(auto_error=True)
app.dependency_overrides[get_current_user_stub] = strict_auth

# Optional authentication (returns None if unauthenticated)
optional_auth = CustomAuth(auto_error=False)
app.dependency_overrides[get_optional_user_stub] = optional_auth

When auto_error=False, missing tokens, expired tokens, or inactive accounts return None gracefully instead of raising an AuthError (401), allowing downstream routes to serve unauthenticated requests while letting Zchema prune fields defined in __private__.


4. Scope-Based Authorization (HasScopes)

ZCore employs an OAuth2/OIDC compatible scope authorization model via the HasScopes permission class:

  • Scope Resolution: Resolves user scopes dynamically from ctx.get("scopes") or the UserProtocol instance.
  • Superuser Bypass: If allow_superuser=True (default), users with is_superuser = True bypass scope assertions entirely, simplifying administrative workflows.
  • Standardized Status Codes:
    • Unauthenticated or inactive user $\rightarrow$ 401 Unauthorized.
    • Insufficient scopes $\rightarrow$ 403 Forbidden.
from fastapi import APIRouter, Depends
from zcore.security import HasScopes

router = APIRouter()

@router.delete(
    "/finance/invoices/{id}",
    dependencies=[Depends(HasScopes("invoices:delete", "finance:admin"))]
)
async def delete_invoice(id: str):
    return {"status": "deleted"}

Zero-Boilerplate Routing: When using BaseRouter, HasScopes dependencies are automatically calculated and injected for every CRUD/Lookup endpoint based on model.actions().

On this page