Files
docs/py-jwt/wiki/search/search_index.json
Vishesh 'ironeagle' Bangotra b3b1c3404b feat: collect py-jwt wiki; register wiki kind; refresh lib and mcp artifacts
Adds the py-jwt wiki to the hub alongside lib and mcp and picks up
the regenerated flat lib reference and standardized MCP modules.
2026-09-16 20:08:15 +05:30

1 line
19 KiB
JSON

{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"\ud83d\udd10 py-jwt \u2014 JWT Authentication Library","text":"<p>Doc model: This wiki describes the runtime, architectural, and integration behavior of <code>jwtlib</code> \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.</p> <p><code>jwtlib</code> 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.</p>"},{"location":"#key-features","title":"\ud83d\ude80 Key Features","text":"<ul> <li>Pure logic, any framework \u2014 no FastAPI/Flask coupling; drop it into any async application.</li> <li>Token introspection \u2014 verify any JWT and resolve its user without static sessions or a shared session store.</li> <li>Request authentication \u2014 logic-only <code>authenticate_request</code> guard for the callers that need an authorization decision.</li> <li>Pluggable persistence \u2014 <code>UserRepository</code> is injected; ship the provided MongoDB-backed default or implement your own.</li> <li>Typed end to end \u2014 Pydantic request/response models for every operation, with full <code>.pyi</code> stubs published for consumers.</li> </ul>"},{"location":"#quick-start","title":"\u26a1 Quick Start","text":"<pre><code>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</code></pre> <p>See How to Use for registration, session checks, and introspection flows.</p>"},{"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 Wiring <code>jwtlib</code> into FastAPI and resource servers Development Setup, tests, and docforge build <p>The reference implementations of these skills live in the auth-server service.</p>"},{"location":"#related-resources","title":"\ud83d\udd17 Related Resources","text":"<ul> <li>Source Code: Gitea Repository</li> <li>Internal PyPI: pip.aetoskia.com/simple/py-jwt</li> <li>Reference service: auth-server \u2014 the canonical service built on <code>jwtlib</code></li> <li>CI: Builds and publishes tagged releases, gated on black / ruff / mypy / pytest.</li> </ul> <p>\u00a9 Aetoskia Internal \u2014 py-jwt 0.0.4</p>"},{"location":"01_overview/","title":"\ud83e\udde0 Overview","text":"<p><code>jwtlib</code> 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.</p>"},{"location":"01_overview/#architecture","title":"\ud83c\udfd7\ufe0f Architecture","text":"<pre><code>\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</code></pre>"},{"location":"01_overview/#public-api-layers","title":"\ud83e\udde9 Public API layers","text":""},{"location":"01_overview/#authentication-operations-jwtlibapp","title":"Authentication operations (<code>jwtlib.app</code>)","text":"Function Purpose <code>register_user(user, repo=None)</code> Create a user from <code>RegisterRequest</code> <code>login_user(user, repo=None)</code> Verify credentials, issue an access token <code>get_logged_in_user(token, repo=None)</code> Resolve the token's subject to a user <code>logout_user()</code> Model the client-side logout signal <code>introspect_token(token, repo=None)</code> Verify a token and produce an introspection verdict <p>Every operation is an <code>async</code> function; the default <code>UserRepository</code> is a MongoDB-backed implementation of the repository contract.</p>"},{"location":"01_overview/#introspection-helpers-jwtlibintrospection","title":"Introspection helpers (<code>jwtlib.introspection</code>)","text":"<ul> <li><code>introspect_token(token)</code> \u2014 decode and validate the JWT.</li> <li><code>authenticate_request(token)</code> \u2014 pure authorization decision for request guards (no framework context required).</li> </ul>"},{"location":"01_overview/#domain-models-jwtlibmodels","title":"Domain models (<code>jwtlib.models</code>)","text":"<ul> <li>Requests: <code>RegisterRequest</code> (username, email, password), <code>LoginRequest</code> (username, password), <code>IntrospectRequest</code> (token).</li> <li>Responses: <code>LoginResponse</code> (access_token + user), <code>LogoutResponse</code> (message), <code>IntrospectResponse</code> (active + user or null).</li> <li>Payloads: <code>TokenPayload</code> (subject + expiry).</li> <li>Persistence: <code>User</code> (identity, active state) with optional email.</li> <li>Mixins: <code>IdentityMixin</code>, <code>PasswordMixin</code>, <code>ActiveStateMixin</code> for custom repository models.</li> </ul>"},{"location":"01_overview/#errors-jwtlibexceptions","title":"Errors (<code>jwtlib.exceptions</code>)","text":"<p><code>AuthError</code> is the base for <code>InvalidToken</code>, <code>InvalidAuthorizationHeader</code>, <code>UserNotFound</code>, <code>AuthServiceUnavailable</code>, and <code>NotAuthenticated</code>.</p>"},{"location":"01_overview/#security-posture","title":"\ud83d\udd12 Security posture","text":"<ul> <li>Passwords are hashed during registration and compared only through the repository's <code>authenticate_user</code>; hashes never leave the persistence layer.</li> <li>Tokens are validated at introspection time (signature, expiry, subject).</li> <li>The library returns typed verdict objects instead of raw framework errors, so callers can map failures to their own HTTP semantics.</li> </ul>"},{"location":"01_overview/#read-next","title":"\ud83d\udcda Read Next","text":"<ul> <li>How to Use \u2014 concrete coroutine flows.</li> <li>Framework Integration \u2014 FastAPI + resource servers.</li> </ul>"},{"location":"02_how_to_use/","title":"\ud83d\udcd6 How to Use","text":"<p>All operations are plain <code>async</code> functions that work identically under FastAPI, Flask, a CLI, or a script. Substitute your own repository to change the persistence backend.</p>"},{"location":"02_how_to_use/#register-a-user","title":"\u270d\ufe0f Register a user","text":"<pre><code>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</code></pre> <p>Returns a <code>PublicUser</code>. Registration hashes the password before it reaches the repository.</p>"},{"location":"02_how_to_use/#log-in","title":"\ud83d\udd11 Log in","text":"<pre><code>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</code></pre> <p>A successful login returns <code>LoginResponse</code> with an access token and the public user. Failures raise <code>AuthError</code> subclasses; catch them and map to your HTTP semantics (e.g. 401).</p>"},{"location":"02_how_to_use/#check-the-current-user","title":"\ud83d\udc64 Check the current user","text":"<pre><code>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</code></pre> <p>Resolves the token subject to a <code>PublicUser</code>. Raises <code>InvalidToken</code> if the token is missing, expired, or malformed, and <code>UserNotFound</code> if the subject no longer exists.</p>"},{"location":"02_how_to_use/#log-out","title":"\ud83d\udeaa Log out","text":"<pre><code>from jwtlib import logout_user\n\nresult = await logout_user()\nprint(result.message)\n</code></pre> <p>Logout is a client-side signal: the returned <code>LogoutResponse</code> tells the caller to discard the stored token. Stateless services should simply stop using the token after logout.</p>"},{"location":"02_how_to_use/#introspect-a-token","title":"\ud83d\udd0e Introspect a token","text":"<p>Verify an arbitrary token and get a structured verdict:</p> <pre><code>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</code></pre> <p><code>IntrospectResponse</code> also provides result helpers used by the canonical service for error mapping. For a pure boolean authorization check:</p> <pre><code>from jwtlib.introspection import authenticate_request\n\nok = await authenticate_request(bearer_token) # True / False\n</code></pre>"},{"location":"02_how_to_use/#injecting-a-custom-repository","title":"\ud83d\udc89 Injecting a custom repository","text":"<p>Every operation accepts an optional <code>repo</code>. Provide your own <code>UserRepository</code>-compatible object to swap storage:</p> <pre><code>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</code></pre>"},{"location":"02_how_to_use/#read-next","title":"\ud83d\udcda Read Next","text":"<ul> <li>Framework Integration \u2014 FastAPI dependency wiring.</li> <li>Overview \u2014 architecture and models.</li> </ul>"},{"location":"03_integration/","title":"\ud83d\udd0c Framework Integration","text":"<p><code>jwtlib</code> is intentionally framework-agnostic. This page shows the idiomatic wiring used by the canonical <code>auth-server</code> service.</p>"},{"location":"03_integration/#fastapi-dependency","title":"\u2699\ufe0f FastAPI dependency","text":"<p>Expose the token from the <code>Authorization</code> header and resolve it to a user via a dependency:</p> <pre><code>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(...)) -&gt; 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</code></pre> <p>On any auth failure the dependency translates <code>AuthError</code> into a 401 \u2014 the library never couples to the HTTP layer.</p>"},{"location":"03_integration/#resource-server-microservice","title":"\ud83d\udce1 Resource server / microservice","text":"<p>A consumer service that does not own the user database can verify tokens via introspection without a shared session store:</p> <pre><code>from jwtlib.introspection import authenticate_request\n\n\nasync def is_allowed(authorization: str) -&gt; bool:\n scheme, _, token = authorization.partition(\" \")\n if scheme.lower() != \"bearer\":\n return False\n return await authenticate_request(token)\n</code></pre>"},{"location":"03_integration/#routing-tokens","title":"\ud83e\udded Routing tokens","text":"<ul> <li>First-party services \u2014 use <code>get_logged_in_user</code> (and the <code>TOKEN_SECRET_KEY</code> they share) for a direct lookup.</li> <li>Third-party / external clients \u2014 validate against the <code>auth-server/introspect</code> endpoint for a standard introspection response.</li> <li>Static vetoes \u2014 use <code>authenticate_request</code> when you only need allow/deny.</li> </ul> <p>Keep <code>Authorization: Bearer &lt;token&gt;</code> consistent across all callers.</p>"},{"location":"03_integration/#error-mapping-cheat-sheet","title":"\u26a0\ufe0f Error mapping cheat-sheet","text":"Raised exception Typical HTTP result <code>InvalidAuthorizationHeader</code> 401 \u2014 malformed header <code>InvalidToken</code> 401 \u2014 expired, bad signature, or malformed <code>UserNotFound</code> 401 \u2014 subject no longer exists <code>AuthServiceUnavailable</code> 503 \u2014 upstream auth unavailable <code>NotAuthenticated</code> 401 \u2014 missing credentials"},{"location":"03_integration/#read-next","title":"\ud83d\udcda Read Next","text":"<ul> <li>How to Use \u2014 the underlying coroutine flows.</li> <li>Development \u2014 contributing to <code>jwtlib</code>.</li> </ul>"},{"location":"04_development/","title":"\ud83d\udee0\ufe0f Development","text":"<p>Working on <code>jwtlib</code> itself.</p>"},{"location":"04_development/#repository-layout","title":"\ud83d\udcc2 Repository layout","text":"Path Purpose <code>jwtlib/</code> The library package (app, introspection, models, repository, security, utils, exceptions) <code>jwtlib/*.pyi</code> Type stubs published alongside the implementations <code>tests/</code> Auth-flow tests (register \u2192 login \u2192 verify \u2192 logout) <code>docs/lib/</code> Generated library reference (docforge, flat layout) <code>docs/mcp/</code> Machine-readable bundle served by the MCP server <code>docs/wiki/</code> This hand-written wiki"},{"location":"04_development/#setup","title":"\ud83d\udd27 Setup","text":"<pre><code>python -m venv .venv\n.venv/Scripts/pip install -e \".[dev]\"\n</code></pre>"},{"location":"04_development/#tests","title":"\ud83e\uddea Tests","text":"<pre><code>.venv/Scripts/python -m pytest\n</code></pre> <p>The suite drives the full async auth flow: registration, login, duplicate handling, session lookup, logout, and introspection.</p>"},{"location":"04_development/#quality-gates","title":"\u2705 Quality gates","text":"<p>The CI quality gate runs, matching the Drone pipeline:</p> <pre><code>.venv/Scripts/black --check .\n.venv/Scripts/ruff check .\n.venv/Scripts/mypy\n.venv/Scripts/python -m pytest\n</code></pre>"},{"location":"04_development/#building-documentation-docforge","title":"\ud83d\udcdd Building documentation (docforge)","text":"<p>The site is generated by <code>docforge</code> and served per kind under <code>site/{kind}</code>:</p> <pre><code>doc-forge build \\\n --mkdocs --mcp --wiki \\\n --module-is-source --module jwtlib \\\n --site-name \"JWT Authentication Library\"\n</code></pre> <ul> <li><code>--module-is-source</code> renders the flat <code>docs/lib/</code> layout (no nesting under <code>jwtlib/</code>), matching <code>docforge.nav.yml</code> and <code>docs/mkdocs.lib.yml</code>.</li> <li><code>--mcp</code> regenerates the structured bundle in <code>docs/mcp/</code>.</li> <li><code>--wiki</code> builds this wiki.</li> </ul> <p>Preview locally:</p> <pre><code>doc-forge serve --lib\ndoc-forge serve --wiki\ndoc-forge serve --mcp\n</code></pre>"},{"location":"04_development/#security-checklist","title":"\ud83d\udd12 Security checklist","text":"<ul> <li>Never log passwords, tokens, or hash material.</li> <li>Keep new flows pure: models in <code>models/</code>, token logic in <code>security.py</code>, orchestration in <code>app.py</code>.</li> <li>Add a regression test for every auth behavior change.</li> </ul>"},{"location":"04_development/#read-next","title":"\ud83d\udcda Read Next","text":"<ul> <li>How to Use \u2014 public API in action.</li> <li>Overview \u2014 architecture.</li> </ul>"}]}