{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"\ud83d\udd10 py-jwt \u2014 JWT Authentication Library","text":"
Doc model: This wiki describes the runtime, architectural, and integration behavior of jwtlib \u2014 the pure, framework-agnostic JWT authentication logic powering service auth. For the full API reference and machine-readable surface, see the Library and MCP tabs.
jwtlib provides pure logic components for user registration, login, token introspection, and authentication verification. It has no web-framework dependencies: FastAPI, Flask, or plain asyncio apps can use the same coroutine-based API.
authenticate_request guard for the callers that need an authorization decision.UserRepository is injected; ship the provided MongoDB-backed default or implement your own..pyi stubs published for consumers.import asyncio\nfrom jwtlib import login_user, LoginRequest\n\nasync def main():\n response = await login_user(LoginRequest(username=\"admin\", password=\"password\"))\n print(response.access_token)\n print(response.user.username)\n\nasyncio.run(main())\n See How to Use for registration, session checks, and introspection flows.
"},{"location":"#documentation-structure","title":"\ud83d\udcd6 Documentation Structure","text":"Section Description Overview Architecture, layers, and public API surface How to Use Register, login, session lookup, logout, introspection Framework Integration Wiringjwtlib into FastAPI and resource servers Development Setup, tests, and docforge build The reference implementations of these skills live in the auth-server service.
"},{"location":"#related-resources","title":"\ud83d\udd17 Related Resources","text":"jwtlib\u00a9 Aetoskia Internal \u2014 py-jwt 0.0.4
"},{"location":"01_overview/","title":"\ud83e\udde0 Overview","text":"jwtlib is a small, focused authentication library. It keeps transport concerns out of auth logic so the same code backs an API service and a CLI or test harness.
\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Your application \u2502\n\u2502 (FastAPI / Flask / CLI / tests) \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n \u2502 coroutine API\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25bc\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 jwtlib.app \u2502\n\u2502 register_user \u00b7 login_user \u00b7 get_logged_in_user \u2502\n\u2502 logout_user \u00b7 introspect_token \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 jwtlib.introspection \u2502 jwtlib.security (token ops) \u2502\n\u2502 authenticate_request \u2502 \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25bc\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 jwtlib.models \u2502\n\u2502 RegisterRequest \u00b7 LoginRequest \u00b7 LoginResponse \u2502\n\u2502 PublicUser \u00b7 IntrospectRequest \u00b7 IntrospectResponse \u2502\n\u2502 TokenPayload \u00b7 User \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 jwtlib.repository \u2502\n\u2502 UserRepository (MongoDB-backed default) \u2502\n\u2502 \u25b2 \u2502\n\u2502 inject your own repository for other backends \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n"},{"location":"01_overview/#public-api-layers","title":"\ud83e\udde9 Public API layers","text":""},{"location":"01_overview/#authentication-operations-jwtlibapp","title":"Authentication operations (jwtlib.app)","text":"Function Purpose register_user(user, repo=None) Create a user from RegisterRequest login_user(user, repo=None) Verify credentials, issue an access token get_logged_in_user(token, repo=None) Resolve the token's subject to a user logout_user() Model the client-side logout signal introspect_token(token, repo=None) Verify a token and produce an introspection verdict Every operation is an async function; the default UserRepository is a MongoDB-backed implementation of the repository contract.
jwtlib.introspection)","text":"introspect_token(token) \u2014 decode and validate the JWT.authenticate_request(token) \u2014 pure authorization decision for request guards (no framework context required).jwtlib.models)","text":"RegisterRequest (username, email, password), LoginRequest (username, password), IntrospectRequest (token).LoginResponse (access_token + user), LogoutResponse (message), IntrospectResponse (active + user or null).TokenPayload (subject + expiry).User (identity, active state) with optional email.IdentityMixin, PasswordMixin, ActiveStateMixin for custom repository models.jwtlib.exceptions)","text":"AuthError is the base for InvalidToken, InvalidAuthorizationHeader, UserNotFound, AuthServiceUnavailable, and NotAuthenticated.
authenticate_user; hashes never leave the persistence layer.All operations are plain async functions that work identically under FastAPI, Flask, a CLI, or a script. Substitute your own repository to change the persistence backend.
import asyncio\nfrom jwtlib import register_user, RegisterRequest\n\nasync def main():\n user = await register_user(\n RegisterRequest(username=\"admin\", email=\"admin@aetoskia.com\", password=\"hunter2\")\n )\n print(user.username, user.is_active)\n\nasyncio.run(main())\n Returns a PublicUser. Registration hashes the password before it reaches the repository.
from jwtlib import login_user, LoginRequest\n\nresponse = await login_user(LoginRequest(username=\"admin\", password=\"hunter2\"))\n\nresponse.access_token # store this in the Authorization header\nresponse.user.username\n A successful login returns LoginResponse with an access token and the public user. Failures raise AuthError subclasses; catch them and map to your HTTP semantics (e.g. 401).
from jwtlib import get_logged_in_user\n\nuser = await get_logged_in_user(bearer_token)\nprint(user.username, user.email, user.is_active)\n Resolves the token subject to a PublicUser. Raises InvalidToken if the token is missing, expired, or malformed, and UserNotFound if the subject no longer exists.
from jwtlib import logout_user\n\nresult = await logout_user()\nprint(result.message)\n Logout is a client-side signal: the returned LogoutResponse tells the caller to discard the stored token. Stateless services should simply stop using the token after logout.
Verify an arbitrary token and get a structured verdict:
from jwtlib import introspect_token\n\nverdict = await introspect_token(bearer_token)\n\nverdict.active # True when the token is valid\nverdict.user.username # resolved subject, or None\n IntrospectResponse also provides result helpers used by the canonical service for error mapping. For a pure boolean authorization check:
from jwtlib.introspection import authenticate_request\n\nok = await authenticate_request(bearer_token) # True / False\n"},{"location":"02_how_to_use/#injecting-a-custom-repository","title":"\ud83d\udc89 Injecting a custom repository","text":"Every operation accepts an optional repo. Provide your own UserRepository-compatible object to swap storage:
from jwtlib import login_user, LoginRequest\n\nclass MyRepo:\n async def get_by_username(self, username: str): ...\n async def authenticate_user(self, user_auth: LoginRequest): ...\n\nresponse = await login_user(LoginRequest(username=\"admin\", password=\"x\"), repo=MyRepo())\n"},{"location":"02_how_to_use/#read-next","title":"\ud83d\udcda Read Next","text":"jwtlib is intentionally framework-agnostic. This page shows the idiomatic wiring used by the canonical auth-server service.
Expose the token from the Authorization header and resolve it to a user via a dependency:
from fastapi import Depends, FastAPI, HTTPException, status\nfrom jwtlib import get_logged_in_user\nfrom jwtlib.exceptions import AuthError\n\napp = FastAPI()\n\n\ndef bearer_token(authorization: str = Header(...)) -> str:\n scheme, _, token = authorization.partition(\" \")\n if scheme.lower() != \"bearer\" or not token:\n raise HTTPException(status.HTTP_401_UNAUTHORIZED, \"Invalid authorization header\")\n return token\n\n\nasync def current_user(token: str = Depends(bearer_token)):\n try:\n return await get_logged_in_user(token)\n except AuthError:\n raise HTTPException(status.HTTP_401_UNAUTHORIZED, \"Not authenticated\")\n\n\n@app.get(\"/me\")\nasync def me(user=Depends(current_user)):\n return {\"username\": user.username, \"email\": user.email}\n On any auth failure the dependency translates AuthError into a 401 \u2014 the library never couples to the HTTP layer.
A consumer service that does not own the user database can verify tokens via introspection without a shared session store:
from jwtlib.introspection import authenticate_request\n\n\nasync def is_allowed(authorization: str) -> bool:\n scheme, _, token = authorization.partition(\" \")\n if scheme.lower() != \"bearer\":\n return False\n return await authenticate_request(token)\n"},{"location":"03_integration/#routing-tokens","title":"\ud83e\udded Routing tokens","text":"get_logged_in_user (and the TOKEN_SECRET_KEY they share) for a direct lookup.auth-server/introspect endpoint for a standard introspection response.authenticate_request when you only need allow/deny.Keep Authorization: Bearer <token> consistent across all callers.
InvalidAuthorizationHeader 401 \u2014 malformed header InvalidToken 401 \u2014 expired, bad signature, or malformed UserNotFound 401 \u2014 subject no longer exists AuthServiceUnavailable 503 \u2014 upstream auth unavailable NotAuthenticated 401 \u2014 missing credentials"},{"location":"03_integration/#read-next","title":"\ud83d\udcda Read Next","text":"jwtlib.Working on jwtlib itself.
jwtlib/ The library package (app, introspection, models, repository, security, utils, exceptions) jwtlib/*.pyi Type stubs published alongside the implementations tests/ Auth-flow tests (register \u2192 login \u2192 verify \u2192 logout) docs/lib/ Generated library reference (docforge, flat layout) docs/mcp/ Machine-readable bundle served by the MCP server docs/wiki/ This hand-written wiki"},{"location":"04_development/#setup","title":"\ud83d\udd27 Setup","text":"python -m venv .venv\n.venv/Scripts/pip install -e \".[dev]\"\n"},{"location":"04_development/#tests","title":"\ud83e\uddea Tests","text":".venv/Scripts/python -m pytest\n The suite drives the full async auth flow: registration, login, duplicate handling, session lookup, logout, and introspection.
"},{"location":"04_development/#quality-gates","title":"\u2705 Quality gates","text":"The CI quality gate runs, matching the Drone pipeline:
.venv/Scripts/black --check .\n.venv/Scripts/ruff check .\n.venv/Scripts/mypy\n.venv/Scripts/python -m pytest\n"},{"location":"04_development/#building-documentation-docforge","title":"\ud83d\udcdd Building documentation (docforge)","text":"The site is generated by docforge and served per kind under site/{kind}:
doc-forge build \\\n --mkdocs --mcp --wiki \\\n --module-is-source --module jwtlib \\\n --site-name \"JWT Authentication Library\"\n --module-is-source renders the flat docs/lib/ layout (no nesting under jwtlib/), matching docforge.nav.yml and docs/mkdocs.lib.yml.--mcp regenerates the structured bundle in docs/mcp/.--wiki builds this wiki.Preview locally:
doc-forge serve --lib\ndoc-forge serve --wiki\ndoc-forge serve --mcp\n"},{"location":"04_development/#security-checklist","title":"\ud83d\udd12 Security checklist","text":"models/, token logic in security.py, orchestration in app.py.