Skip to main content

JWT auth for HawkAPI — access + refresh tokens, password hashing, DI guards

Project description

hawkapi-auth

JWT auth for HawkAPI. Access + refresh tokens, argon2id password hashing, DI guards, scope-based access control.

Install

pip install hawkapi-auth

Quickstart

from hawkapi import Depends, HawkAPI, HTTPException
from hawkapi_auth import (
    JWTConfig,
    hash_password,
    init_auth,
    random_secret,
    requires_user,
    verify_password,
)

app = HawkAPI()
init_auth(app, config=JWTConfig(secret=random_secret()))


@app.post("/register")
async def register(email: str, password: str):
    await db.create_user(email=email, password_hash=hash_password(password))
    return {"ok": True}


@app.post("/login")
async def login(email: str, password: str):
    user = await db.find_user(email)
    if not user or not verify_password(password, user.password_hash):
        raise HTTPException(401, detail="Invalid credentials")
    issuer = app.state.auth
    return {
        "access_token": issuer.issue_access(user.id),
        "refresh_token": issuer.issue_refresh(user.id),
    }


@app.get("/me")
async def me(user_id: str = Depends(requires_user)):
    return await db.fetch_user(user_id)

Token issue / verify

issuer = app.state.auth      # TokenIssuer

access = issuer.issue_access("user-1", role="admin", scope="read write")
refresh = issuer.issue_refresh("user-1")

claims = issuer.verify_access(access)        # raises TokenError on bad token
claims = issuer.verify_refresh(refresh)      # ditto, plus checks the token type

issue_access / issue_refresh accept arbitrary keyword claims (role, scope, anything JSON-serialisable).

JWTConfig

JWTConfig(
    secret="…",                  # HMAC secret for HS256/384/512
    algorithm="HS256",
    access_ttl_seconds=15 * 60,
    refresh_ttl_seconds=30 * 24 * 60 * 60,
    issuer="my-service",          # optional iss claim
    audience="my-api",            # optional aud claim
    private_key="",               # RS*/ES* — PEM
    public_key="",
)

Use random_secret() to mint one. Store it outside of git.

DI guards

from hawkapi_auth import requires_user, requires_claims, requires_scopes

@app.get("/me")
async def me(user_id: str = Depends(requires_user)):
    ...

@app.get("/dump")
async def dump(claims: dict = Depends(requires_claims)):
    ...

@app.get("/admin", dependencies=[Depends(requires_scopes("admin"))])
async def admin():
    ...

requires_scopes(*scopes) expects either a space-separated scope claim or a list under scope / scopes. Missing scopes → 403.

Refresh + revocation

from hawkapi_auth import RevocationList

rev = RevocationList()
init_auth(app, config=JWTConfig(secret=...), revocation=rev)

@app.post("/refresh")
async def refresh(refresh_token: str):
    issuer = app.state.auth
    claims = issuer.verify_refresh(refresh_token)
    return {"access_token": issuer.issue_access(claims["sub"])}

@app.post("/logout")
async def logout(refresh_token: str):
    app.state.auth.revoke_refresh(refresh_token)
    return {"ok": True}

RevocationList is in-memory only. For multi-process deployments, swap in a Redis-backed implementation (planned in v0.2.0).

Password hashing

from hawkapi_auth import hash_password, verify_password, needs_rehash

h = hash_password("hunter2")              # argon2id
ok = verify_password("hunter2", h)        # constant-time, returns bool
if needs_rehash(h):
    h = hash_password("hunter2")          # re-hash after a successful login

verify_password never raises — safe to use directly in handler bodies.

What's not included (v0.2.0 roadmap)

  • Social OAuth providers (Google / GitHub / Discord / Microsoft).
  • Email-based password reset + verification flows.
  • Pre-built user model and storage.
  • Redis-backed RevocationList.

Development

git clone https://github.com/ashimov/hawkapi-auth.git
cd hawkapi-auth
uv sync --extra dev
uv run pytest -q
uv run ruff check . && uv run ruff format --check .
uv run pyright src/

License

MIT.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

hawkapi_auth-0.2.0.tar.gz (29.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

hawkapi_auth-0.2.0-py3-none-any.whl (10.6 kB view details)

Uploaded Python 3

File details

Details for the file hawkapi_auth-0.2.0.tar.gz.

File metadata

  • Download URL: hawkapi_auth-0.2.0.tar.gz
  • Upload date:
  • Size: 29.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for hawkapi_auth-0.2.0.tar.gz
Algorithm Hash digest
SHA256 d286082645f9b043dc1e3116a851aa7f08ab15907c683a9ebdf37a0c701af392
MD5 2dcf4357d0d937546e13004fff2f2e4e
BLAKE2b-256 4c5d9370b43c13e64db75c495d2f09422538c6bfa33e43f8f60ecb2b3d73d36c

See more details on using hashes here.

Provenance

The following attestation bundles were made for hawkapi_auth-0.2.0.tar.gz:

Publisher: release.yml on ashimov/hawkapi-auth

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file hawkapi_auth-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: hawkapi_auth-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 10.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for hawkapi_auth-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1fe78e4e3a1cf404c5b680415fa7f27b82170a1d179b4f1829e75ad7367af9b0
MD5 4fd7d6fbaf92bb6f154527ec5d954033
BLAKE2b-256 3409d7fe968696574c639f0669f7315cee054f66789db6bf942c9436bef3adfc

See more details on using hashes here.

Provenance

The following attestation bundles were made for hawkapi_auth-0.2.0-py3-none-any.whl:

Publisher: release.yml on ashimov/hawkapi-auth

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page