Skip to main content

JWT, API key auth, bcrypt hashing, and scoped principals for AI-native platforms

Project description

nodus-auth

JWT issuance/validation, API key hashing, bcrypt passwords, and scoped principals for AI-native platforms.

Standalone auth primitives — no FastAPI required. All core functions work with any Python web framework or no framework at all.

Status: v0.1.0 — prepared, not yet published.


Install

pip install nodus-auth

bcrypt version note: This package pins bcrypt>=4.0.1,<5.0 because passlib 1.7.4 is incompatible with bcrypt 5.x. Do not upgrade bcrypt beyond 4.x in the same environment.


What it provides

Component Purpose
KeyRing / create_access_token / decode_access_token JWT issuance and verification with key rotation
hash_password / verify_password bcrypt password hashing via passlib
generate_key / hash_key API key generation and SHA-256 storage hash
AuthPrincipal / Scopes Resolved identity with scope-based access control
LoginRequest / RegisterRequest / TokenResponse Pydantic request/response schemas
parse_user_id / require_user_id UUID parsing helpers
AuthSettings pydantic-settings config for SECRET_KEY, ALGORITHM, expiry

JWT tokens

from nodus_auth import AuthSettings, create_access_token, decode_access_token, InvalidTokenError

settings = AuthSettings(SECRET_KEY="my-secret-key-32-chars-minimum")
token = create_access_token({"sub": "user-123"}, settings=settings)

try:
    payload = decode_access_token(token, settings=settings)
    user_id = payload["sub"]
except InvalidTokenError:
    # expired, malformed, or wrong key
    ...

Key rotation

from nodus_auth import KeyRing, create_access_token, decode_access_token, AuthSettings

ring = KeyRing(active="key-v1", grace_hours=24)
settings = AuthSettings(SECRET_KEY="key-v1")
token = create_access_token({"sub": "u1"}, settings=settings, key_ring=ring)

ring.rotate("key-v2")  # tokens signed with key-v1 still verify for 24 hours
payload = decode_access_token(token, settings=settings, key_ring=ring)  # OK

decode_access_token tries the active key first, then any keys within their grace period. Tokens outside their grace window raise InvalidTokenError.


Passwords

from nodus_auth import hash_password, verify_password

hashed = hash_password("correct-horse-battery-staple")
assert verify_password("correct-horse-battery-staple", hashed)
assert not verify_password("wrong-password", hashed)

API keys

from nodus_auth import generate_key, hash_key

raw_key, key_hash = generate_key()
# Deliver raw_key to the caller once; store key_hash in the database
assert hash_key(raw_key) == key_hash

generate_key() uses secrets.token_urlsafe. The raw key is never stored; the SHA-256 hash is used for all comparisons.


Scoped principals

from nodus_auth import AuthPrincipal, Scopes

principal = AuthPrincipal(
    user_id="user-123",
    auth_type="api_key",
    scopes=[Scopes.MEMORY_READ, Scopes.FLOW_EXECUTE],
)
assert principal.has_scope(Scopes.FLOW_EXECUTE)
assert not principal.has_scope(Scopes.PLATFORM_ADMIN)

auth_type is "jwt" or "api_key". Scopes provides well-known constants: MEMORY_READ, MEMORY_WRITE, FLOW_EXECUTE, FLOW_CREATE, PLATFORM_ADMIN.


AuthSettings

from nodus_auth import AuthSettings

# Reads from environment variables: SECRET_KEY, ALGORITHM, ACCESS_TOKEN_EXPIRE_MINUTES
settings = AuthSettings()

# Or explicit:
settings = AuthSettings(
    SECRET_KEY="...",
    ALGORITHM="HS256",
    ACCESS_TOKEN_EXPIRE_MINUTES=60,
)

User ID helpers

from nodus_auth import parse_user_id, require_user_id, parse_user_ids
import uuid

parse_user_id("550e8400-e29b-41d4-a716-446655440000")  # → UUID
parse_user_id(None)                                     # → None
require_user_id("not-a-uuid")                           # raises ValueError
parse_user_ids(["uid-1", "bad", "uid-2"])              # → [UUID, UUID]  (skips failures)

Dependencies

Package Version Purpose
python-jose ≥3.5.0 JWT encoding/decoding
passlib ≥1.7.4 bcrypt password context
bcrypt ≥4.0.1,<5.0 bcrypt backend (passlib 1.7.4 incompatible with 5.x)
pydantic ≥2.0.0 Schemas
pydantic-settings ≥2.0.0 AuthSettings from env vars

Development

pip install -e ".[dev]"
pytest tests/ -q

License

MIT — see LICENSE.

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

nodus_auth-0.1.0.tar.gz (11.8 kB view details)

Uploaded Source

Built Distribution

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

nodus_auth-0.1.0-py3-none-any.whl (9.8 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: nodus_auth-0.1.0.tar.gz
  • Upload date:
  • Size: 11.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for nodus_auth-0.1.0.tar.gz
Algorithm Hash digest
SHA256 b180dd45a801c32a58dc3a7e28a9b17f5bfdba407a54edfa8dd44673e0d8850f
MD5 3f0bd92a7c85321019ccdcc21d263b44
BLAKE2b-256 9c555276864f64dea5bad8c5382497095a7d142c60420f170ee6abd6eeadf8ce

See more details on using hashes here.

File details

Details for the file nodus_auth-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: nodus_auth-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 9.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for nodus_auth-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 fe0eb7d488a2169870783ac4fe1f27dc975d525d8cb184fc6f73a327238dfafa
MD5 7df1b75c9d59c15abbd19a109565ab94
BLAKE2b-256 dfe76a1760dc32fe15b9a016ba01b0e212493d655ead360508684598b0f66854

See more details on using hashes here.

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