Authentication for hayate as a pure fetch(Request) -> Response handler: email+password, sessions, CSRF
Project description
hayate-auth
Standards-first authentication for hayate — a mountable, better-auth-style auth handler built on the WHATWG Request/Response model.
Status: alpha (0.5.x). Email+password, sessions, CSRF, email verification, password reset, OAuth 2.1 + PKCE (Google / GitHub), TOTP two-factor, and API keys are implemented and attack-regression-tested; a
generateCLI and a Cloudflare D1 adapter ship too. Not yet security-audited — see SECURITY.md. The internal design memo (Japanese) lives in DESIGN.md.
import os
from hayate import Hayate
from hayate_auth import Auth
from hayate_auth.adapters.sqlite import SQLiteAdapter
adapter = SQLiteAdapter("app.db")
adapter.create_tables()
auth = Auth(secret=os.environ["AUTH_SECRET"], adapter=adapter)
app = Hayate()
auth.register(app) # serves /api/auth/* (sign-up, sign-in, session, ...)
@app.get("/me", auth.require_session())
async def me(c):
return c.json(c.get("user"))
The same file runs under any ASGI server and on Cloudflare Python Workers — see examples/todo.
Endpoints
Method / path (under /api/auth) |
Purpose |
|---|---|
POST /sign-up/email |
Register with email + password, start a session |
POST /sign-in/email |
Verify credentials, start a session |
GET /get-session |
Current {user, session} (or nulls) |
POST /sign-out |
Revoke the session server-side |
POST /forget-password → /reset-password |
Reset flow via a one-shot hashed token |
GET /verify-email |
Confirm an email with a one-shot token |
POST /sign-in/social → GET /callback/:provider |
OAuth 2.1 + PKCE (Google / GitHub) |
POST /two-factor/enable · /verify · /disable |
TOTP (RFC 6238) enrollment |
POST /sign-in/two-factor |
Second step when 2FA is on |
POST /api-key/create · /verify · /delete · GET /api-key/list |
API keys (hashed, scoped, expiring) |
API keys double as the bridge to hayate-mcp:
auth.verify_api_key plugs straight into its OAuth Resource Server, so an API
key protects an MCP server in one line:
from hayate_mcp import Authorization, McpMount
McpMount(server, authorization=Authorization(
resource="https://mcp.example.com",
authorization_servers=["https://auth.example.com"],
verify_token=auth.verify_api_key,
)).register(app)
With TOTP enabled, /sign-in/email returns {"two_factor_required": true} plus
a short-lived signed challenge cookie instead of a session; the client then
posts the authenticator code to /sign-in/two-factor to get the session — so a
stolen password alone never signs in.
Email delivery is your callback (send_reset_password / send_verification_email);
the core mints and verifies tokens but never builds URLs or sends mail. Generate
migration DDL with python -m hayate_auth generate --dialect sqlite|postgres|d1.
OAuth providers are injected; the token exchange runs over hayate-fetch, so it works on ASGI and Workers alike:
from hayate_auth import Auth, google, github
auth = Auth(
secret=os.environ["AUTH_SECRET"],
adapter=adapter,
providers=[
google(client_id=..., client_secret=...),
github(client_id=..., client_secret=...),
],
)
Why
- Python has no equivalent of better-auth: a framework-agnostic, self-hosted, schema-owning auth library. django-allauth is Django-only; fastapi-users is in maintenance mode.
- better-auth works on every JS framework because its core is a single
fetch(Request) -> Responsehandler. hayate is the only Python framework whose user-facing surface is WHATWG Request/Response — so that architecture finally maps 1:1 to Python. - Zero-dependency core (its only dependency is hayate, itself zero-dependency). Databases, KDFs, and email are injected protocols.
Security posture
- Passwords: scrypt at OWASP parameters (N=2^17, r=8, p=1) on every runtime, PBKDF2-HMAC-SHA256 (600k) fallback; PHC-style strings make the backends mutually verifiable. Length-only policy per NIST SP 800-63B.
- Sessions: opaque 256-bit tokens, only their SHA-256 stored;
__Host--prefixed HttpOnly SameSite=Lax cookies on HTTPS. - CSRF: SameSite + Origin (RFC 6454) + Fetch Metadata — no token embedding.
- Sign-in failures are uniform in body and KDF timing (enumeration defense).
- Coverage ledger: docs/asvs.md (OWASP ASVS V6/V7, ratcheted).
- You must rate-limit
/api/auth/*(hayate middleware or your infrastructure): brute-force throttling is deliberately out of core.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file hayate_auth-0.5.0.tar.gz.
File metadata
- Download URL: hayate_auth-0.5.0.tar.gz
- Upload date:
- Size: 23.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
79f2e0983f76bdc720b5d4e89d1d6c7fd1dc73521c35015ecca448dfd205118b
|
|
| MD5 |
cf5cd7c64d7a668fa97bdc3c1652f72f
|
|
| BLAKE2b-256 |
6d13b9db8e17ca0f815216adc9f55cfc6fcb12fdb810b3afdb4781ec0b0e8275
|
Provenance
The following attestation bundles were made for hayate_auth-0.5.0.tar.gz:
Publisher:
release.yml on hayatepy/hayate-auth
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hayate_auth-0.5.0.tar.gz -
Subject digest:
79f2e0983f76bdc720b5d4e89d1d6c7fd1dc73521c35015ecca448dfd205118b - Sigstore transparency entry: 2220014588
- Sigstore integration time:
-
Permalink:
hayatepy/hayate-auth@76cf91f64ce9e03cde6a04b565e31af252edfab7 -
Branch / Tag:
refs/tags/v0.5.0 - Owner: https://github.com/hayatepy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@76cf91f64ce9e03cde6a04b565e31af252edfab7 -
Trigger Event:
push
-
Statement type:
File details
Details for the file hayate_auth-0.5.0-py3-none-any.whl.
File metadata
- Download URL: hayate_auth-0.5.0-py3-none-any.whl
- Upload date:
- Size: 33.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4cb401f684509157ff98ff9d4681583974f597a8d826bd06a81b71c90640af4e
|
|
| MD5 |
0552320d8a764f49915ad856d1c1dd21
|
|
| BLAKE2b-256 |
a4d76e583c85ccd42006f4529371771c412f1d9c600cd7f0ba67120da3c26baf
|
Provenance
The following attestation bundles were made for hayate_auth-0.5.0-py3-none-any.whl:
Publisher:
release.yml on hayatepy/hayate-auth
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hayate_auth-0.5.0-py3-none-any.whl -
Subject digest:
4cb401f684509157ff98ff9d4681583974f597a8d826bd06a81b71c90640af4e - Sigstore transparency entry: 2220014612
- Sigstore integration time:
-
Permalink:
hayatepy/hayate-auth@76cf91f64ce9e03cde6a04b565e31af252edfab7 -
Branch / Tag:
refs/tags/v0.5.0 - Owner: https://github.com/hayatepy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@76cf91f64ce9e03cde6a04b565e31af252edfab7 -
Trigger Event:
push
-
Statement type: