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.1.0.tar.gz (27.4 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.1.0-py3-none-any.whl (9.8 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: hawkapi_auth-0.1.0.tar.gz
  • Upload date:
  • Size: 27.4 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.1.0.tar.gz
Algorithm Hash digest
SHA256 f426d406a39e2a831b57af454238e723d070cc641626ea2264319d24e7fe77a9
MD5 60c63d0be909669b7dc720264b7ffb92
BLAKE2b-256 41cc2455c4351149a9722b5a445b5de5114c6e91eb16187a807a3cd5341180ff

See more details on using hashes here.

Provenance

The following attestation bundles were made for hawkapi_auth-0.1.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.1.0-py3-none-any.whl.

File metadata

  • Download URL: hawkapi_auth-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 9.8 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.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 35db02326303d065c62b12769438646a3ee2959970d0db7f46ba7808fedd6095
MD5 4c10e4ee3b63d1721414f900af1c66f3
BLAKE2b-256 fc22a3c2e10389acb46387c2dcec6c9acf5b6210d900746d91cefc852f1d93f1

See more details on using hashes here.

Provenance

The following attestation bundles were made for hawkapi_auth-0.1.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