nyxa-auth — JWT / session auth & policies for Nyxa
Authentication and authorization for apps built with
nyxa. Core nyxa does not
depend on this package (no JWT in the core install).
At a glance
| What you need | Nyxa Auth |
|---|---|
| Protect routes | Route.middleware(require_auth) or CurrentUser Depends |
| Current user | get_current_user / CurrentUser / core user() stubs |
| Policies | Policy subclasses under policies/ + authorize(...) |
| Hash / verify passwords | hash_password / verify_password |
| JWT tokens | create_access_token (AUTH_DRIVER=jwt, default) |
| Cookie sessions | login_user / logout_user + configure_session (AUTH_DRIVER=session) |
| Personal access tokens (PATs) | create_personal_token + set_token_lookup (Bearer alongside JWT) |
| OAuth (Google/GitHub) | create_authorize_redirect / complete_oauth_login + oauth_identities (nyxa-auth[oauth]) |
Install
uv add nyxa-auth
uv add 'nyxa-auth[oauth]' # Authlib — Google / GitHub OAuth
# JWT (default driver):
uv run nyxa init myapi --database sqlite --auth jwt --no-input
# Session cookies:
uv run nyxa init myapi --database sqlite --auth session --no-input
JWT driver
AUTH_DRIVER=jwt
AUTH_SECRET_KEY=change-me-to-a-long-random-secret!!
# AUTH_ALGORITHM=HS256
# AUTH_ACCESS_TOKEN_EXPIRE_MINUTES=60
Session driver
AUTH_DRIVER=session
AUTH_SECRET_KEY=change-me-to-a-long-random-secret!!
# AUTH_SESSION_SECRET= # optional override for cookie signing
In main.py:
from nyxa_auth import configure_session, set_user_loader
app = FastAPI()
configure_session(app)
set_user_loader(...)
Login stores user_id in a signed cookie; require_auth reads it instead of Bearer JWT.
Personal access tokens
Requires nyxa-db. Under AUTH_DRIVER=jwt, Bearer auth tries JWT first, then a registered personal-token lookup.
from nyxa_auth import (
create_personal_token,
find_token,
set_token_lookup,
set_user_loader,
)
def lookup(plain: str) -> str | None:
session = get_session_factory()()
try:
row = find_token(session, plain)
if row is None:
return None
session.commit()
return str(row.tokenable_id)
finally:
session.close()
set_user_loader(...)
set_token_lookup(lookup)
# Issue (plaintext once):
issued = create_personal_token(session, user.id, "ci")
# Authorization: Bearer nyxa_<id>_<secret>
Table: personal_access_tokens (hash only). Revoke with revoke_personal_token / revoke_all_for_user.
OAuth (Google + GitHub)
Requires the optional extra and Authlib. Identity rows need nyxa-db:
uv add 'nyxa-auth[oauth]'
OAUTH_GOOGLE_CLIENT_ID=...
OAUTH_GOOGLE_CLIENT_SECRET=...
OAUTH_GOOGLE_REDIRECT_URI=http://127.0.0.1:8000/api/oauth/google/callback
OAUTH_GITHUB_CLIENT_ID=...
OAUTH_GITHUB_CLIENT_SECRET=...
OAUTH_GITHUB_REDIRECT_URI=http://127.0.0.1:8000/api/oauth/github/callback
AUTH_SECRET_KEY=... # also signs the OAuth state cookie
from nyxa_auth import (
clear_oauth_state_cookie,
complete_oauth_login,
create_authorize_redirect,
provider_from_env,
resolve_oauth_identity,
)
provider = provider_from_env("google") # or "github"
# GET /oauth/google/redirect → create_authorize_redirect(request, provider)
# callback → resolve_oauth_identity(...) then complete_oauth_login(...)
# JWT driver returns {"access_token", "token_type"}; session driver returns {"ok": true}
Users are linked by (provider, sub) in oauth_identities. On first login, email
auto-link attaches the identity to an existing user when emails match (trusts the
provider). Existing Google users get an identity row on their next OAuth login.
Quick start
from typing import Annotated
from fastapi import Depends, FastAPI
from nyxa import Route, register
from nyxa_auth import (
CurrentUser,
create_access_token,
hash_password,
require_auth,
set_user_loader,
verify_password,
)
app = FastAPI()
# Map JWT "sub" → your user object (sync callable).
users = {"1": {"id": 1, "email": "ada@example.com", "password_hash": hash_password("secret")}}
set_user_loader(lambda sub: users.get(sub))
register(app)
@app.post("/login")
def login(email: str, password: str) -> dict[str, str]:
user = next((u for u in users.values() if u["email"] == email), None)
if user is None or not verify_password(password, user["password_hash"]):
from nyxa_auth import AuthenticationError
raise AuthenticationError("Invalid credentials")
return {"access_token": create_access_token(str(user["id"])), "token_type": "bearer"}
# Protect a route group:
with Route.prefix("/api"), Route.middleware(require_auth):
Route.get("/me", lambda user: user) # prefer a controller in real apps
Or inject the user on a controller action:
from nyxa_auth import CurrentUser
async def me(self, user: CurrentUser) -> dict:
return {"id": getattr(user, "id", None)}
Policies
uv run nyxa make:policy User
from nyxa_auth import Policy, authorize
class UserPolicy(Policy):
def update(self, user, model=None) -> bool:
return model is not None and user.id == model.id
# In a controller:
authorize(user, UserPolicy, "update", target_user)
Denied abilities raise AuthorizationError (HTTP 403). Missing/invalid
credentials raise AuthenticationError (HTTP 401).
Metadata
Release files for nyxa-auth 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| nyxa_auth-0.1.0.tar.gz | 16.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| nyxa_auth-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 39.1 kB
Release files / nyxa_auth-0.1.0.tar.gz
| Download URL | nyxa_auth-0.1.0.tar.gz |
|---|---|
| Size | 16.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2c292f5177423bf7f9c0327762b09fcbc450dcec885ef3a0b8c838028a22ac27
|
|
BLAKE2b-256 checksum How to use checksums |
64f6a5629cb40ce88beb5adc8c9f283cc27eb230c988d53e7c5646dcadb2e3f9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.20 {"installer":{"name":"uv","version":"0.12.20","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / nyxa_auth-0.1.0-py3-none-any.whl
| Download URL | nyxa_auth-0.1.0-py3-none-any.whl |
|---|---|
| Size | 22.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
51ab2d7a504ef92f7feddfc0fcc669fbb930a1bc3722e6b65197bcd132eb0ebb
|
|
BLAKE2b-256 checksum How to use checksums |
d173a26359580beaa7580fe9f38964d0db1d2b44160ae8ef40bed2a0b08a9451
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.20 {"installer":{"name":"uv","version":"0.12.20","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|