Files
docs/auth-server/wiki/search/search_index.json
Vishesh 'ironeagle' Bangotra a115df113d chore: collect auth-server wiki and lib refresh
Picks up the rewritten auth-server wiki (platform anatomy theme) and the
regenerated lib artifacts, including the new pep-typed marker bounce.
2026-09-16 19:51:24 +05:30

1 line
20 KiB
JSON

{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"\ud83d\udd10 Aetoskia Auth Server \u2014 Central Identity for the Aetos Platform","text":"<p>The Aetoskia Auth Server is the central identity service of the Aetos Platform ecosystem. It issues, validates, and introspects short-lived JWT access tokens against a single shared user store backed by MongoDB, so every service can trust one issuer instead of shipping its own auth logic.</p> <p>Doc model: this wiki is written for humans \u2014 how\u2011to guides, examples, and deployment recipes. The authoritative API contracts live in the code (GSDFC docstrings) and the interactive OpenAPI reference under <code>docs/api/</code>.</p>"},{"location":"#key-features","title":"\ud83d\ude80 Key Features","text":"<ul> <li>\ud83d\udd11 Centralized identity \u2014 one user database, one issuer, one secret</li> <li>\ud83c\udf9f\ufe0f Uniform token contract \u2014 every service verifies the same HS256 JWT</li> <li>\ud83e\udde9 No auth code duplication \u2014 services delegate with <code>jwtlib</code> or a generated OpenAPI dependency</li> <li>\u26a1 Instant revocation surface \u2014 <code>/introspect</code> gives services a live <code>active</code> check rather than trusting expiry alone</li> <li>\ud83d\udd13 Stateless logout \u2014 no server-side sessions; the client discards the token</li> </ul>"},{"location":"#endpoints-at-a-glance","title":"\u26a1 Endpoints at a Glance","text":"Method Path Purpose POST <code>/register</code> Create a user account POST <code>/login</code> Authenticate and issue a JWT GET <code>/me</code> Current user (Bearer) POST <code>/logout</code> Stateless logout (Bearer) POST <code>/introspect</code> Service-to-service token verification GET <code>/health</code> Health check"},{"location":"#documentation-structure","title":"\ud83d\udcc1 Documentation Structure","text":"Section What you'll find Centralized Auth The identity model and how the ecosystem trusts the server How to Use Register, login, and call endpoints with tokens Platform Integration How services authenticate requests Deployment Environment, Docker, and CI/CD Development Local setup, tests, and regenerating docs"},{"location":"#related-resources","title":"\ud83d\udd17 Related Resources","text":"<ul> <li>Source Code: Gitea Repository</li> <li>API Reference: interactive Swagger UI rendered from <code>docs/api/openapi.json</code></li> <li>CI/CD: Drone pipeline ships tagged releases as <code>aetos/auth-server</code> images</li> </ul> <p>\u00a9 Aetoskia Internal \u2014 <code>auth-server</code> 0.0.5</p>"},{"location":"01_centralized_auth/","title":"\ud83d\udd17 Centralized Authentication","text":"<p>The Aetoskia Auth Server acts as the single identity provider for every application in the Aetos Platform ecosystem. The model is deliberately small and uniform.</p>"},{"location":"01_centralized_auth/#the-identity-model","title":"\ud83e\uddec The identity model","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\u2510\n \u2502 Aetoskia Auth Server \u2502\n \u2502 users collection (MongoDB) \u2502\n \u2502 HS256 JWT issuer \u2502\n \u2514\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\u2518\n \u2502 /login \u2192 JWT\n \u2502 /introspect \u2190 verification\n \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n \u2502 \u2502 \u2502\n App A (FastAPI) App B (service) CLI/web clients\n verifies via verifies via\n jwtlib / OpenAPI jwtlib introspect\n dependency\n</code></pre> <ul> <li>One issuer. All access tokens are signed with the same <code>JWT_SECRET</code> using HS256 and carry <code>sub</code> (the username) plus an <code>exp</code> claim.</li> <li>One user store. Users live in the shared MongoDB <code>users</code> collection; passwords are bcrypt-hashed and never leave the server.</li> <li>Shared trust. Any service can validate a token locally with <code>jwtlib</code> (decode + signature) or ask the server via <code>/introspect</code> for a live answer.</li> <li>No shared sessions. Logout is stateless: the token is discarded by the client, and further use is prevented only by expiry or revocation through introspection-driven policies.</li> </ul>"},{"location":"01_centralized_auth/#token-contract","title":"\ud83c\udf9f\ufe0f Token contract","text":"<p>A valid access token is an HS256 JWT with exactly two claims:</p> <pre><code>{\n \"sub\": \"alice\",\n \"exp\": 1750000000\n}\n</code></pre> <ul> <li><code>sub</code> \u2014 the username of the authenticated user.</li> <li><code>exp</code> \u2014 UTC epoch seconds of expiry (60 minutes by default).</li> </ul> <p>There are no scopes or roles inside the token; authorization decisions belong to the consuming service, while identity and authenticity belong here.</p>"},{"location":"01_centralized_auth/#how-the-ecosystem-trusts-the-server","title":"\ud83e\udd1d How the ecosystem trusts the server","text":"<ol> <li>Users authenticate once via <code>/login</code> and receive a token.</li> <li>Services accept that token as proof of identity after verifying it (locally via <code>jwtlib</code> or remotely via <code>/introspect</code>).</li> <li>Sensitive endpoints recover the user profile from the token through <code>get_current_user</code> or the generated dependency \u2014 never by parsing JWTs by hand.</li> </ol> <p>This keeps authentication centralized while leaving each service in control of its own authorization rules.</p>"},{"location":"01_centralized_auth/#benefits","title":"\ud83d\udca1 Benefits","text":"<ul> <li>New services onboard with a client library call, not a new auth system.</li> <li>Credential storage, hashing, and issuance policies evolve in one place.</li> <li>A single <code>JWT_SECRET</code> rotation strategy protects the whole platform.</li> </ul>"},{"location":"01_centralized_auth/#read-next","title":"\ud83d\udcda Read Next","text":"<ul> <li>How to Use \u2014 register, login, and call endpoints.</li> <li>Platform Integration \u2014 wiring the token into services.</li> </ul>"},{"location":"02_how_to_use/","title":"\ud83d\udda5\ufe0f How to Use","text":"<p>This page covers the plain HTTP usage of the auth server: creating users, logging in, and calling protected endpoints with a bearer token.</p>"},{"location":"02_how_to_use/#register-a-user","title":"\ud83d\udc64 Register a user","text":"<pre><code>curl -X POST http://localhost:8000/register \\\n -H \"Content-Type: application/json\" \\\n -d '{\"username\": \"alice\", \"email\": \"alice@aetoskia.com\", \"password\": \"s3cret!\"}'\n</code></pre> <ul> <li><code>username</code> \u2014 3 to 50 characters (required).</li> <li><code>email</code> \u2014 valid email (optional).</li> <li><code>password</code> \u2014 at least 6 characters (required; stored hashed).</li> </ul> <p>Response <code>201 Created</code>:</p> <pre><code>{\n \"username\": \"alice\",\n \"email\": \"alice@aetoskia.com\",\n \"is_active\": true\n}\n</code></pre> <p>The password is never returned.</p>"},{"location":"02_how_to_use/#log-in-to-get-a-token","title":"\ud83d\udd11 Log in to get a token","text":"<pre><code>curl -X POST http://localhost:8000/login \\\n -H \"Content-Type: application/json\" \\\n -d '{\"username\": \"alice\", \"password\": \"s3cret!\"}'\n</code></pre> <p>Response <code>200 OK</code>:</p> <pre><code>{\n \"access_token\": \"&lt;jwt&gt;\",\n \"user\": {\n \"username\": \"alice\",\n \"email\": \"alice@aetoskia.com\",\n \"is_active\": true\n }\n}\n</code></pre> <p>Invalid credentials return <code>401</code> with <code>{\"detail\": \"Invalid credentials\"}</code>.</p>"},{"location":"02_how_to_use/#call-a-protected-endpoint","title":"\ud83d\udd12 Call a protected endpoint","text":"<p>Send the token as a bearer token:</p> <pre><code>curl http://localhost:8000/me \\\n -H \"Authorization: Bearer &lt;jwt&gt;\"\n</code></pre> <p>Response <code>200 OK</code> with the current user profile. A missing or invalid token returns <code>401</code> with <code>WWW-Authenticate: Bearer</code>.</p>"},{"location":"02_how_to_use/#log-out","title":"\ud83d\udeaa Log out","text":"<pre><code>curl -X POST http://localhost:8000/logout \\\n -H \"Authorization: Bearer &lt;jwt&gt;\"\n</code></pre> <p>Logout is stateless \u2014 the server returns a confirmation and the client must discard the token:</p> <pre><code>{ \"message\": \"Successfully logged out. Please discard your token on the client.\" }\n</code></pre>"},{"location":"02_how_to_use/#token-lifecycle-quick-reference","title":"\ud83e\udded Token lifecycle quick reference","text":"Event Endpoint Result Create identity <code>POST /register</code> user profile Obtain token <code>POST /login</code> <code>access_token</code> + user Verify (self) <code>GET /me</code> user profile or <code>401</code> End session <code>POST /logout</code> discard-token confirmation Verify (other services) <code>POST /introspect</code> <code>active</code> + user <p>Interactive examples are available in the API Reference site (Swagger UI), rendered from <code>docs/api/openapi.json</code>.</p>"},{"location":"02_how_to_use/#read-next","title":"\ud83d\udcda Read Next","text":"<ul> <li>Centralized Auth \u2014 the identity model and token contract.</li> <li>Platform Integration \u2014 consuming the token in services.</li> </ul>"},{"location":"03_platform_integration/","title":"\ud83d\udd0c Platform Integration","text":"<p>This page is for service authors wiring authentication into Aetos applications. It covers both supported integration paths.</p>"},{"location":"03_platform_integration/#path-1-jwtlib-client-py-jwt","title":"\ud83e\udde9 Path 1: <code>jwtlib</code> client (<code>py-jwt</code>)","text":"<p>Services that depend on the <code>py-jwt</code> library can authenticate requests without an OpenAPI generator. Set the auth server base URL:</p> <pre><code>export JWT_SERVER=http://auth.aetoskia.com\n</code></pre> <p>Then verify incoming requests:</p> <pre><code>from jwtlib.introspection import authenticate_request\n\nauthorized = await authenticate_request(\n should_skip_authentication, # e.g. allow public paths\n method,\n path,\n authorization_token, # \"Bearer &lt;jwt&gt;\" or None\n)\n</code></pre> <p><code>authenticate_request</code> POSTs <code>{\"token\": \"&lt;jwt&gt;\"}</code> to <code>{JWT_SERVER}/introspect</code> (3 second timeout) and treats <code>{\"active\": true, \"user\": {...}}</code> as valid. Transport errors surface as <code>AuthServiceUnavailable</code>.</p> <p>For zero-request validation (offline token decode), <code>jwtlib</code> also exposes the token payload helpers used by the auth server itself \u2014 see the <code>py-jwt</code> documentation.</p>"},{"location":"03_platform_integration/#path-2-openapi-first-generated-dependencies","title":"\ud83d\udee0\ufe0f Path 2: <code>openapi-first</code> generated dependencies","text":"<p>Services declared with an OpenAPI-first contract can generate their FastAPI dependencies from the spec. Declare a bearer security scheme pointing at the auth server:</p> <pre><code>securitySchemes:\n HTTPBearer:\n type: http\n scheme: bearer\n x-server-url: https://auth.aetoskia.com\n x-introspect-path: /introspect\n</code></pre> <p>The generated dependency then POSTs <code>{\"token\": token}</code> to the introspection path and returns the user on <code>active == true</code>, raising <code>401</code> on invalid or inactive tokens and <code>503</code> when the auth server is unreachable.</p>"},{"location":"03_platform_integration/#the-introspect-contract","title":"\ud83d\udccb The <code>/introspect</code> contract","text":"Field Type Description request <code>token</code> (string) The JWT to verify response <code>active</code> (bool) Whether the token is valid and active response <code>user</code> (PublicUser | null) The profile when active <p>The endpoint always answers <code>200</code> \u2014 validity is expressed through <code>active</code>. <code>IntrospectResponse</code> never raises, so the caller can act on the tri-state (valid / invalid / user missing) without exception handling.</p>"},{"location":"03_platform_integration/#protecting-endpoints-in-fastapi","title":"\ud83d\udc0d Protecting endpoints in FastAPI","text":"<p>For first-party services, mount the auth router's dependency directly:</p> <pre><code>from fastapi import Depends\nfrom jwtlib import PublicUser\nfrom jwt import get_current_user\n\n@app.get(\"/profile\")\nasync def profile(current_user: PublicUser = Depends(get_current_user)):\n return current_user\n</code></pre>"},{"location":"03_platform_integration/#golden-rules","title":"\u26a0\ufe0f Golden rules","text":"<ol> <li>Never trust an unverified token \u2014 always decode through <code>jwtlib</code> or introspect before handling the request.</li> <li>Treat <code>active: false</code> as unauthenticated, even if the JWT decodes.</li> <li>Do not implement your own JWT parsing \u2014 use a generated dependency or the <code>jwtlib</code> client so revocation and issuer changes stay centralized.</li> </ol>"},{"location":"03_platform_integration/#read-next","title":"\ud83d\udcda Read Next","text":"<ul> <li>How to Use \u2014 the plain HTTP flow.</li> <li>Deployment \u2014 environment, Docker, and CI/CD.</li> </ul>"},{"location":"04_deployment/","title":"\ud83d\ude80 Deployment","text":"<p>How the auth server is configured and shipped.</p>"},{"location":"04_deployment/#environment-variables","title":"\u2699\ufe0f Environment variables","text":"Variable Required Default Purpose <code>MONGO_HOST</code> yes \u2014 MongoDB host <code>MONGO_USER</code> no \u2014 MongoDB username <code>MONGO_PASS</code> no \u2014 MongoDB password <code>MONGO_PORT</code> no <code>27017</code> MongoDB port <code>MONGO_DB_NAME</code> no <code>auth</code> Database name <code>JWT_SECRET</code> no* <code>superstrongsecretkey</code> Token signing secret (*set in production!) <p>Credentials and the token secret live in the environment / Deploy secrets \u2014 see <code>.env.example</code> for the shape. <code>.env</code> is gitignored.</p>"},{"location":"04_deployment/#running-locally","title":"\ud83d\udcbb Running locally","text":"<pre><code>cp .env.example .env # fill in MONGO_HOST, JWT_SECRET\nuvicorn main:app --reload --port 8000\n</code></pre> <p>The health endpoint is available at <code>GET /health</code>.</p>"},{"location":"04_deployment/#container-image","title":"\ud83d\udc33 Container image","text":"<p>The <code>Dockerfile</code> is a multi-stage build on <code>python:3.13-slim</code>:</p> <ol> <li>Builder installs <code>requirements.txt</code> from the private pip index using build args <code>PIP_USERNAME</code>, <code>PIP_PASSWORD</code>, <code>PIP_REPO_URL</code>.</li> <li>Runtime copies Python 3.13 from the builder, installs <code>curl</code>, exposes port <code>8000</code>, and runs <code>uvicorn main:app</code>. A <code>HEALTHCHECK</code> curls <code>/health</code>.</li> </ol>"},{"location":"04_deployment/#cicd-drone","title":"\ud83d\udd04 CI/CD (Drone)","text":"<p><code>.drone.yml</code> ships on git tag events (arm64):</p> <ol> <li>Resolve the latest tag.</li> <li>Skip if the image already exists.</li> <li><code>docker build</code> with pip credentials (secrets) \u2192 <code>aetos/auth-server:$TAG</code> and <code>:latest</code>.</li> <li>Push to <code>$REGISTRY_HOST/aetos/auth-server:*</code>.</li> <li>Restart the running container <code>auth-server</code>.</li> </ol> <p>The deployed container runs with <code>--restart always</code>, maps host <code>9003</code> \u2192 <code>8000</code>, resolves <code>private-pi</code> to <code>192.168.1.111</code> for Mongo, and receives <code>MONGO_*</code> + <code>JWT_SECRET</code> from secrets.</p>"},{"location":"04_deployment/#environments","title":"\ud83c\udf0d Environments","text":"Environment Base URL Production <code>https://auth.aetoskia.com</code> Internal staging <code>http://server-pi:9002</code> Local development <code>http://localhost:8000</code>"},{"location":"04_deployment/#read-next","title":"\ud83d\udcda Read Next","text":"<ul> <li>Platform Integration \u2014 the <code>/introspect</code> contract.</li> <li>Development \u2014 local setup, tests, and docs.</li> </ul>"},{"location":"05_development/","title":"\ud83d\udee0\ufe0f Development","text":"<p>Working on the auth server itself.</p>"},{"location":"05_development/#repository-layout","title":"\ud83d\udcc2 Repository layout","text":"Path Purpose <code>main.py</code> FastAPI app factory, environment wiring, lifespan, OpenAPI customization <code>jwt/</code> The auth routes package (<code>router</code>, <code>get_current_user</code>) <code>generate_spec.py</code> Regenerates the committed OpenAPI spec <code>docs/api/</code> API reference (Swagger UI embed + <code>openapi.json</code>) <code>docs/lib/</code> Generated library reference (docforge) <code>docs/wiki/</code> This hand-written wiki <code>tests/</code> Async route tests against an in-memory Mongo mock"},{"location":"05_development/#setup","title":"\ud83d\udd27 Setup","text":"<pre><code>python -m venv .venv\n.venv/Scripts/pip install -r requirements.txt\n</code></pre> <p>Dependencies are installed from the private pip index (see <code>requirements.txt</code> and the <code>Dockerfile</code>). Core runtime packages:</p> <ul> <li><code>py-jwt==0.0.4</code> \u2014 provides <code>jwtlib</code> (applications logic, models, security, introspection)</li> <li><code>mongo-ops==0.1.3</code> \u2014 MongoDB persistence layer</li> <li><code>fastapi</code>, <code>uvicorn</code>, <code>python-jose</code>, <code>passlib</code>, <code>bcrypt</code>, <code>pymongo</code></li> </ul>"},{"location":"05_development/#tests","title":"\ud83e\uddea Tests","text":"<p>Run the suite (no network or Mongo required \u2014 an in-memory mock is used):</p> <pre><code>.venv/Scripts/pytest --asyncio-mode=auto\n</code></pre> <p>Coverage spans the full HTTP flow: register \u2192 login \u2192 wrong-password <code>401</code> \u2192 <code>/me</code> with and without a token \u2192 stateless logout.</p>"},{"location":"05_development/#regenerating-the-openapi-spec","title":"\ud83d\udcdc Regenerating the OpenAPI spec","text":"<p>The committed <code>docs/api/openapi.json</code> is produced offline:</p> <pre><code>set MONGO_HOST=127.0.0.1\npython generate_spec.py\n</code></pre> <p><code>MONGO_HOST</code> only needs to be set for the import; no connection is opened.</p>"},{"location":"05_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 --api --openapi-spec docs/api/openapi.json \\\n --mkdocs --wiki \\\n --module jwt \\\n --site-name \"Aetoskia Auth Server\"\n</code></pre> <ul> <li><code>--api</code> renders <code>openapi.json</code> with Swagger UI.</li> <li><code>--mkdocs</code> renders the library reference from the <code>jwt</code> package docstrings (nested under <code>docs/lib/jwt/</code>, matching <code>docforge.nav.yml</code>).</li> <li><code>--wiki</code> builds this wiki.</li> <li>Navigation layout is defined in <code>docforge.nav.yml</code>.</li> </ul> <p>The <code>jwt</code> module is rendered without <code>--module-is-source</code> so the library output stays nested under <code>docs/lib/jwt/</code>, matching the committed <code>docs/mkdocs.lib.yml</code> nav.</p> <p>Preview locally:</p> <pre><code>doc-forge serve --api\ndoc-forge serve --lib\ndoc-forge serve --wiki\n</code></pre>"},{"location":"05_development/#read-next","title":"\ud83d\udcda Read Next","text":"<ul> <li>Deployment \u2014 environment and CI/CD.</li> <li>How to Use \u2014 exercising the service end to end.</li> </ul>"}]}