feat(standards): integrate auth-server via pinned spec (docs://spec) + auth recipe and template slice
- serve the pinned auth-server OpenAPI contract as the standards MCP resource docs://spec (no auth-server MCP bundle) - add Auth Integration recipe (14) and wire it into the registry, prompts, index, and nav - un-defer Auth Server in the library registry (spec/recipe pointers) - ship the opt-in template auth slice: interfaces/auth/ (placeholder + mergeable bearerAuth security.yaml) and AUTH_SERVER/JWT_SERVER env - rebuild bundle (13 modules, 44 components); template stays authless by default
This commit is contained in:
@@ -42,6 +42,12 @@
|
||||
"placeholder": "",
|
||||
"description": "Route registry: flat re-export of every handler namespace."
|
||||
},
|
||||
{
|
||||
"kind": "auth",
|
||||
"path": "interfaces/auth/security.yaml",
|
||||
"placeholder": "",
|
||||
"description": "Mergeable bearerAuth security scheme + global security for openapi.yaml."
|
||||
},
|
||||
{
|
||||
"kind": "test-model",
|
||||
"path": "tests/unit/test_item_models.py",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"project": "standards",
|
||||
"type": "standards",
|
||||
"modules_count": 12,
|
||||
"modules_count": 13,
|
||||
"source": "hand-authored"
|
||||
}
|
||||
@@ -68,12 +68,13 @@
|
||||
},
|
||||
{
|
||||
"name": "Auth Server",
|
||||
"import": "auth-server",
|
||||
"purpose": "Central identity service (register/login/me/introspect).",
|
||||
"import": null,
|
||||
"purpose": "Central identity service (register/login/me/logout/introspect).",
|
||||
"use_instead_of": "building authentication endpoints yourself",
|
||||
"capabilities": ["auth", "identity", "service", "register", "login", "introspect"],
|
||||
"status": "deferred",
|
||||
"mcp": { "server": null, "port": null, "note": "service; no MCP bundle; deferred" }
|
||||
"capabilities": ["auth", "identity", "service", "register", "login", "logout", "introspect", "bearer"],
|
||||
"spec": "docs://spec",
|
||||
"recipe": "docs://modules/auth_integration",
|
||||
"mcp": { "server": null, "port": null, "note": "service; read contract via docs://spec; no MCP bundle" }
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
8
standards/mcp/modules/auth_integration.json
Normal file
8
standards/mcp/modules/auth_integration.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"module": "auth_integration",
|
||||
"content": {
|
||||
"path": "auth_integration",
|
||||
"docstring": "# Auth Integration\n\n## Summary\n\nAuthentication is a **service**, not a library. Every Aetos application shares a\nsingle identity service — the **auth-server** — and consumes it through its HTTP\ncontract. An app never implements registration, login, password hashing, or\ntoken issuance itself.\n\nThe agent does **not** need an MCP bundle for the auth-server. It reads the\npinned OpenAPI contract (below) and declares a bearer security scheme in its own\nspec; `openapi_first` then generates the verifying dependency. **No auth code is\nwritten.**\n\n---\n\n## Read the contract\n\nThe auth-server OpenAPI document is pinned in the standards bundle and served as\nan MCP resource:\n\n```\ndocs://spec\n```\n\nIt is the authoritative client contract (OpenAPI 3.1). Read it to learn the\nendpoints and the request/response schemas:\n\n| Endpoint | Purpose |\n|---|---|\n| `POST /register` | Create a user (201, returns `PublicUser`) |\n| `POST /login` | Authenticate and issue a JWT (`LoginResponse`) |\n| `GET /me` | Current user's `PublicUser` (bearer required) |\n| `POST /logout` | Stateless logout (`LogoutResponse`) |\n| `POST /introspect` | Internal token introspection (`active`, `user`) |\n\nThe pinned snapshot is versioned (currently `0.0.5`). If the caller has a live\nauth-server and needs the *current* contract, they can pass the full endpoint\n(`{AUTH_SERVER}/openapi.json`) and read it directly instead of the pin.\n\n---\n\n## Wire it up: declare, don't code\n\nAuthentication is added by editing the app's **own** `openapi.yaml` — nothing\nelse. Declare a global bearer requirement and point the scheme at the auth\nserver (values come from the environment):\n\n```yaml\nsecurity:\n - bearerAuth: []\npaths:\n # ...\ncomponents:\n securitySchemes:\n bearerAuth:\n type: http\n scheme: bearer\n bearerFormat: JWT\n x-server-url: \"{AUTH_SERVER}\"\n x-introspect-path: \"/introspect\"\n x-login-path: \"/login\"\n x-register-path: \"/register\"\n x-logout-path: \"/logout\"\n x-me-path: \"/me\"\n```\n\n`openapi_first` reads `securitySchemes` + `security` and generates a FastAPI\ndependency that extracts the bearer token, POSTs `{\"token\": <jwt>}` to\n`{AUTH_SERVER}/introspect`, and returns the user when `active == true`. It\nraises `401` on an invalid or inactive token and `503` when the auth server is\nunreachable. The generated handlers receive the authenticated user — you author\n**no** authentication code.\n\n### Public operations\n\nA route that must stay open opts out by overriding `security` with an empty\nlist:\n\n```yaml\npaths:\n /health:\n get:\n operationId: health\n security: [] # overrides the global requirement\n responses:\n \"200\":\n description: OK\n```\n\n### Environment\n\n```bash\nAUTH_SERVER=http://localhost:8000 # auth-server base URL\nJWT_SERVER=http://localhost:8000 # jwtlib client base URL (seeding/CLI)\n```\n\n---\n\n## Path 1: `jwtlib` client (no generator)\n\nApps that do not use a generated dependency verify requests with the `py-jwt`\nclient:\n\n```python\nfrom jwtlib.introspection import authenticate_request\n\nauthorized = await authenticate_request(\n should_skip_authentication, # allow public paths\n method,\n path,\n authorization_token, # \"Bearer <jwt>\" or None\n)\n```\n\n`authenticate_request` POSTs to `{JWT_SERVER}/introspect` (3 second timeout) and\ntreats `{\"active\": true, \"user\": {...}}` as valid. Use this for seeding scripts\nand tests (`jwtlib.register_user`, `jwtlib.login_user`).\n\n---\n\n## Golden rules\n\n1. **Never trust an unverified token.** Decode through the generated dependency\n or `jwtlib` before handling the request.\n2. **Treat `active: false` as unauthenticated**, even if the JWT decodes.\n3. **Do not implement your own JWT parsing.** Revocation and issuer changes must\n stay centralized in the auth-server.\n4. **Do not add auth until the app's outcome is validated.** Ship the app\n authless first; layer the security scheme once the core behaviour works.\n\n---\n\n## Notes\n\n- The default template is **authless** on purpose. Add the `securitySchemes`\n block above only when auth is required. Pull the shared slice with\n `get_app_component(\"auth\")`.\n- The auth-server is deployed as a service (no importable package); the client\n surface is the spec, plus `jwtlib` for the low-level path.\n",
|
||||
"objects": {}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
"module": "index",
|
||||
"content": {
|
||||
"path": "index",
|
||||
"docstring": "# Standards Reference\n\nThe reference half of the Standards description: the enforceable rules,\npatterns, and the internal library catalog that agents consult while coding.\n\n- **Build Recipe** — the ordered, agentic checklist for a new app.\n- **Layering Rules** — the strict request → domain → repository layering and\n the rules that enforce it.\n- **Composition Root** — a single composition point wiring the whole app.\n- **Spec-First Routing** — the OpenAPI contract as the routing source of truth.\n- **CRUD Template** — the standardized generic resource endpoint scaffold.\n- **Pipeline Scaffold** — the deterministic pipeline skeleton for multi-stage\n jobs.\n- **Worker & Progress** — queued work, progress reporting, and visibility.\n- **Human-in-the-Loop** — guardrails and approvals inside automations.\n- **Infra Adapters** — how infrastructure connects without leaking into domain.\n- **Genericity Matrix** — what is library-backed, template-provided, or authored.\n- **Library Registry** — the catalog of internal libraries behind all of it.\n\nRead the **Wiki** for the philosophy and rationale; these pages are the\nreference that mirrors the `standards` MCP bundle.\n",
|
||||
"docstring": "# Standards Reference\n\nThe reference half of the Standards description: the enforceable rules,\npatterns, and the internal library catalog that agents consult while coding.\n\n- **Build Recipe** — the ordered, agentic checklist for a new app.\n- **Layering Rules** — the strict request → domain → repository layering and\n the rules that enforce it.\n- **Composition Root** — a single composition point wiring the whole app.\n- **Spec-First Routing** — the OpenAPI contract as the routing source of truth.\n- **CRUD Template** — the standardized generic resource endpoint scaffold.\n- **Pipeline Scaffold** — the deterministic pipeline skeleton for multi-stage\n jobs.\n- **Worker & Progress** — queued work, progress reporting, and visibility.\n- **Human-in-the-Loop** — guardrails and approvals inside automations.\n- **Infra Adapters** — how infrastructure connects without leaking into domain.\n- **Genericity Matrix** — what is library-backed, template-provided, or authored.\n- **Auth Integration** — consuming the shared auth-server service (spec-driven,\n no auth code).\n- **Library Registry** — the catalog of internal libraries behind all of it.\n\nRead the **Wiki** for the philosophy and rationale; these pages are the\nreference that mirrors the `standards` MCP bundle.\n",
|
||||
"objects": {}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
"module": "library_registry",
|
||||
"content": {
|
||||
"path": "library_registry",
|
||||
"docstring": "# Library Registry\n\n## Summary\n\nThe Aetos ecosystem provides internal libraries for the shared concerns of\nevery application. **Use them.** Writing a private copy of any capability below\nis a defect.\n\nEach library also exposes its own documentation as an MCP server. An AI agent\ncan read a library's full API by connecting to its MCP and reading\n`docs://index`, `docs://nav`, and `docs://modules/{module}`.\n\n---\n\n## Catalog\n\n| Library | Import | Purpose | Use instead of | MCP |\n|---|---|---|---|---|\n| DAG Pipe | `dagpipe` | Deterministic state-transformation DAG engine | hand-rolled orchestration/topological ordering | `:8006` |\n| Hexa | `hexa` | Declarative DI / composition-root tooling | manual wiring, hand-written factories | `:8008` |\n| Mongo Ops | `mongo_ops` | Async MongoDB repositories, cache, populate, transactions | raw Motor CRUD and connection lifecycle | `:8007` |\n| Omniread | `omniread` | Format-agnostic fetch + parse (HTML, PDF, CSV, XLSX) | custom scrapers/parsers | `:8003` |\n| OpenAPI First | `openapi_first` | Spec-first FastAPI bootstrap, client, codegen | decorator routers and hand-written clients | `:8004` |\n| Mail Intake | `mail_intake` | Provider-agnostic read-only email ingestion | Gmail OAuth + MIME parsing | `:8002` |\n| Py JWT | `jwtlib` | JWT auth primitives (register/login/introspect) | password hashing + token code | `:8005` |\n| Doc Forge | `docforge` | Docstring compiler → MkDocs + MCP docs | custom doc generators | `:8001` |\n| Auth Server | *(service)* | Central identity service (register/login/me/introspect) | building auth endpoints yourself | *(deferred)* |\n\n## How to choose\n\n| You need to… | Use |\n|---|---|\n| persist and query documents | Mongo Ops |\n| compose dependencies | Hexa |\n| run a multi-step transformation | DAG Pipe |\n| read/parse an arbitrary input format | Omniread |\n| expose a contract-first HTTP API | OpenAPI First |\n| ingest email | Mail Intake |\n| authenticate users / verify tokens | Py JWT (+ Auth Server) |\n| generate documentation | Doc Forge |\n\n## Discovery\n\nA single **standards MCP** exposes `find_library(capability)`, which returns the\nmatching library, its import name, its \"use instead of\" guidance, and its MCP\nendpoint. Query it before writing any infrastructure.\n\n## Notes\n\n- **Hexa** is a full library with its own MCP server on `:8008`: read\n `docs://index`, `docs://nav`, and `docs://modules/{module}` (e.g.\n `docs://modules/hexa.container`) to discover the DI surface — `build(cls, *,\n instances, config)` and the `PortNode` model.\n- **Auth Server** is deferred: it has no `pyproject.toml`/importable package and\n no MCP bundle. Do not reach for it yet; `py-jwt` covers token primitives.\n- Library MCP servers expose **documentation resources** (not executable tools):\n they tell an agent the available API surface so it does not invent code.\n",
|
||||
"docstring": "# Library Registry\n\n## Summary\n\nThe Aetos ecosystem provides internal libraries for the shared concerns of\nevery application. **Use them.** Writing a private copy of any capability below\nis a defect.\n\nEach library also exposes its own documentation as an MCP server. An AI agent\ncan read a library's full API by connecting to its MCP and reading\n`docs://index`, `docs://nav`, and `docs://modules/{module}`.\n\n---\n\n## Catalog\n\n| Library | Import | Purpose | Use instead of | MCP |\n|---|---|---|---|---|\n| DAG Pipe | `dagpipe` | Deterministic state-transformation DAG engine | hand-rolled orchestration/topological ordering | `:8006` |\n| Hexa | `hexa` | Declarative DI / composition-root tooling | manual wiring, hand-written factories | `:8008` |\n| Mongo Ops | `mongo_ops` | Async MongoDB repositories, cache, populate, transactions | raw Motor CRUD and connection lifecycle | `:8007` |\n| Omniread | `omniread` | Format-agnostic fetch + parse (HTML, PDF, CSV, XLSX) | custom scrapers/parsers | `:8003` |\n| OpenAPI First | `openapi_first` | Spec-first FastAPI bootstrap, client, codegen | decorator routers and hand-written clients | `:8004` |\n| Mail Intake | `mail_intake` | Provider-agnostic read-only email ingestion | Gmail OAuth + MIME parsing | `:8002` |\n| Py JWT | `jwtlib` | JWT auth primitives (register/login/introspect) | password hashing + token code | `:8005` |\n| Doc Forge | `docforge` | Docstring compiler → MkDocs + MCP docs | custom doc generators | `:8001` |\n| Auth Server | *(service)* | Central identity service (register/login/me/logout/introspect) | building auth endpoints yourself | spec: `docs://spec` |\n\n## How to choose\n\n| You need to… | Use |\n|---|---|\n| persist and query documents | Mongo Ops |\n| compose dependencies | Hexa |\n| run a multi-step transformation | DAG Pipe |\n| read/parse an arbitrary input format | Omniread |\n| expose a contract-first HTTP API | OpenAPI First |\n| ingest email | Mail Intake |\n| authenticate users / verify tokens | Py JWT (+ Auth Server) |\n| generate documentation | Doc Forge |\n\n## Discovery\n\nA single **standards MCP** exposes `find_library(capability)`, which returns the\nmatching library, its import name, its \"use instead of\" guidance, and its MCP\nendpoint (or, for the auth-server service, a spec pointer). It also serves the\npinned auth-server OpenAPI contract at `docs://spec`. Query it before writing\nany infrastructure.\n\n## Notes\n\n- **Hexa** is a full library with its own MCP server on `:8008`: read\n `docs://index`, `docs://nav`, and `docs://modules/{module}` (e.g.\n `docs://modules/hexa.container`) to discover the DI surface — `build(cls, *,\n instances, config)` and the `PortNode` model.\n- **Auth Server** is a **service**, not an importable library: it has no MCP\n bundle by design. Read its client contract from the pinned OpenAPI document\n via `docs://spec` and wire it by declaring a `bearerAuth` security scheme in\n the app's own spec (see **Auth Integration**); `py-jwt` covers the\n low-level token path.\n- Library MCP servers expose **documentation resources** (not executable tools):\n they tell an agent the available API surface so it does not invent code.\n",
|
||||
"objects": {}
|
||||
}
|
||||
}
|
||||
@@ -54,6 +54,11 @@
|
||||
"resource": "docs://modules/library_registry",
|
||||
"title": "Library Registry"
|
||||
},
|
||||
{
|
||||
"module": "auth_integration",
|
||||
"resource": "docs://modules/auth_integration",
|
||||
"title": "Auth Integration"
|
||||
},
|
||||
{
|
||||
"module": "index",
|
||||
"resource": "docs://modules/index",
|
||||
|
||||
563
standards/mcp/specs/auth-server.json
Normal file
563
standards/mcp/specs/auth-server.json
Normal file
@@ -0,0 +1,563 @@
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
"info": {
|
||||
"title": "Aetoskia Auth Server",
|
||||
"description": "\n The Aetoskia Authentication Service.\n\n Provides identity, access control, and JWT token issuance for the Aetoskia\n ecosystem. Fully async, built with FastAPI and MongoDB.\n ",
|
||||
"termsOfService": "https://aetoskia.com/terms",
|
||||
"contact": {
|
||||
"name": "Aetoskia Dev Team",
|
||||
"url": "https://dev.aetoskia.com/contact",
|
||||
"email": "dev@aetoskia.com"
|
||||
},
|
||||
"license": {
|
||||
"name": "MIT License",
|
||||
"url": "https://opensource.org/licenses/MIT"
|
||||
},
|
||||
"version": "0.0.5"
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
"url": "https://auth.aetoskia.com",
|
||||
"description": "Production Authentication Service"
|
||||
},
|
||||
{
|
||||
"url": "http://server-pi:9002",
|
||||
"description": "Internal staging environment"
|
||||
},
|
||||
{
|
||||
"url": "http://localhost:8000",
|
||||
"description": "Local development server"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"/register": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Auth"
|
||||
],
|
||||
"summary": "Register a new user",
|
||||
"description": "Creates a new user account and returns the public user profile.",
|
||||
"operationId": "create_user_register_post",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/RegisterRequest"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PublicUser"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/HTTPValidationError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/login": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Auth"
|
||||
],
|
||||
"summary": "Login user",
|
||||
"description": "Authenticates a user and issues a JWT access token.",
|
||||
"operationId": "login_login_post",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/LoginRequest"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/LoginResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/HTTPValidationError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/me": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Auth"
|
||||
],
|
||||
"summary": "Get current user",
|
||||
"description": "Returns the currently authenticated user's public profile.",
|
||||
"operationId": "read_users_me_me_get",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PublicUser"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"HTTPBearer": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/logout": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Auth"
|
||||
],
|
||||
"summary": "Logout user",
|
||||
"description": "Stateless logout endpoint. The client must discard the JWT access token.",
|
||||
"operationId": "logout_logout_post",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/LogoutResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"HTTPBearer": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/introspect": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Auth",
|
||||
"Internal"
|
||||
],
|
||||
"summary": "Token introspection (internal)",
|
||||
"description": "Internal service-to-service endpoint for verifying JWTs. Not intended for direct client use.",
|
||||
"operationId": "introspect_introspect_post",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/IntrospectRequest"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/IntrospectResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/HTTPValidationError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/health": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Health"
|
||||
],
|
||||
"summary": "Health Check",
|
||||
"description": "Report service health.\n\nReturns:\n dict:\n A simple ``{\"status\": \"ok\"}`` payload used by load balancers and\n the container health check.",
|
||||
"operationId": "health_check_health_get",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"schemas": {
|
||||
"HTTPValidationError": {
|
||||
"properties": {
|
||||
"detail": {
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/ValidationError"
|
||||
},
|
||||
"type": "array",
|
||||
"title": "Detail"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"title": "HTTPValidationError"
|
||||
},
|
||||
"IntrospectRequest": {
|
||||
"properties": {
|
||||
"token": {
|
||||
"type": "string",
|
||||
"title": "Token",
|
||||
"description": "JWT access token to introspect",
|
||||
"examples": [
|
||||
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"required": [
|
||||
"token"
|
||||
],
|
||||
"title": "IntrospectRequest",
|
||||
"description": "Payload for requesting token introspection.\n\nUsed by internal services to verify the validity of a JWT and retrieve\nthe associated public user information.\n\nFields:\n token: JWT access token to introspect.\n\nNotes:\n - Intended for service-to-service communication.\n - Not meant for direct end-user consumption.",
|
||||
"example": {
|
||||
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||
}
|
||||
},
|
||||
"IntrospectResponse": {
|
||||
"properties": {
|
||||
"active": {
|
||||
"type": "boolean",
|
||||
"title": "Active",
|
||||
"description": "Indicates whether the provided token is valid and active",
|
||||
"examples": [
|
||||
true,
|
||||
false
|
||||
]
|
||||
},
|
||||
"user": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/PublicUser"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Public user details if the token is valid; null otherwise"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"required": [
|
||||
"active"
|
||||
],
|
||||
"title": "IntrospectResponse",
|
||||
"description": "Result of a token introspection operation.\n\nThis model communicates whether a JWT is valid and, if so, provides\nthe associated public user information.\n\nFields:\n active: Indicates whether the token is valid and active.\n user: Public user details if the token is valid; otherwise null.\n\nNotes:\n - This model is designed to avoid raising exceptions.\n - All introspection outcomes are represented as data.",
|
||||
"example": {
|
||||
"active": true,
|
||||
"user": {
|
||||
"email": "tester@example.com",
|
||||
"is_active": true,
|
||||
"username": "tester"
|
||||
}
|
||||
}
|
||||
},
|
||||
"LoginRequest": {
|
||||
"properties": {
|
||||
"password": {
|
||||
"type": "string",
|
||||
"minLength": 6,
|
||||
"title": "Password",
|
||||
"description": "User password (minimum 6 characters). Stored only as a hash.",
|
||||
"examples": [
|
||||
"SuperSecure123"
|
||||
]
|
||||
},
|
||||
"username": {
|
||||
"type": "string",
|
||||
"maxLength": 50,
|
||||
"minLength": 3,
|
||||
"title": "Username",
|
||||
"description": "Unique username used for authentication and display",
|
||||
"examples": [
|
||||
"tester"
|
||||
]
|
||||
},
|
||||
"email": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"format": "email"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Email",
|
||||
"description": "Primary email address associated with the account",
|
||||
"examples": [
|
||||
"tester@example.com"
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"required": [
|
||||
"password",
|
||||
"username"
|
||||
],
|
||||
"title": "LoginRequest",
|
||||
"description": "Payload for authenticating a user and issuing a JWT.\n\nThis model is used to verify user credentials and request an access token.\n\nFields:\n username: Username identifier.\n password: Plain-text password to be verified.\n\nNotes:\n - Successful authentication results in a LoginResponse.\n - Failed authentication raises an AuthError.",
|
||||
"example": {
|
||||
"password": "SuperSecure123",
|
||||
"username": "tester"
|
||||
}
|
||||
},
|
||||
"LoginResponse": {
|
||||
"properties": {
|
||||
"access_token": {
|
||||
"type": "string",
|
||||
"title": "Access Token",
|
||||
"description": "JWT access token to be used for authenticated requests",
|
||||
"examples": [
|
||||
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||
]
|
||||
},
|
||||
"user": {
|
||||
"$ref": "#/components/schemas/PublicUser",
|
||||
"description": "Authenticated user's public profile"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"required": [
|
||||
"access_token",
|
||||
"user"
|
||||
],
|
||||
"title": "LoginResponse",
|
||||
"description": "Response returned after successful authentication.\n\nContains the issued JWT access token and the authenticated user's\npublic profile.\n\nFields:\n access_token: JWT access token for authenticated requests.\n user: Public profile of the authenticated user.\n\nNotes:\n - The token is stateless and must be stored client-side.\n - Token expiration and validation are handled elsewhere.",
|
||||
"example": {
|
||||
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||||
"user": {
|
||||
"email": "tester@example.com",
|
||||
"is_active": true,
|
||||
"username": "tester"
|
||||
}
|
||||
}
|
||||
},
|
||||
"LogoutResponse": {
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string",
|
||||
"title": "Message",
|
||||
"description": "Human-readable logout confirmation message",
|
||||
"examples": [
|
||||
"Successfully logged out"
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"required": [
|
||||
"message"
|
||||
],
|
||||
"title": "LogoutResponse",
|
||||
"description": "Response returned after a logout operation.\n\nSince logout is stateless, this response serves only as a confirmation\nmessage instructing the client to discard its token.\n\nFields:\n message: Human-readable logout confirmation.",
|
||||
"example": {
|
||||
"message": "Successfully logged out"
|
||||
}
|
||||
},
|
||||
"PublicUser": {
|
||||
"properties": {
|
||||
"is_active": {
|
||||
"type": "boolean",
|
||||
"title": "Is Active",
|
||||
"description": "Indicates whether the account is active and allowed to authenticate",
|
||||
"default": true,
|
||||
"examples": [
|
||||
true
|
||||
]
|
||||
},
|
||||
"username": {
|
||||
"type": "string",
|
||||
"maxLength": 50,
|
||||
"minLength": 3,
|
||||
"title": "Username",
|
||||
"description": "Unique username used for authentication and display",
|
||||
"examples": [
|
||||
"tester"
|
||||
]
|
||||
},
|
||||
"email": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"format": "email"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Email",
|
||||
"description": "Primary email address associated with the account",
|
||||
"examples": [
|
||||
"tester@example.com"
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"required": [
|
||||
"username"
|
||||
],
|
||||
"title": "PublicUser",
|
||||
"description": "Public-facing user representation returned by authentication APIs.\n\nThis model represents a user profile that is safe to expose outside\nthe authentication system.\n\nFields:\n username: Unique username identifier.\n email: User's email address.\n is_active: Whether the user account is active.\n\nNotes:\n - Contains no sensitive data.\n - Can be constructed from persistence models via `from_attributes`.",
|
||||
"example": {
|
||||
"email": "tester@example.com",
|
||||
"is_active": true,
|
||||
"username": "tester"
|
||||
}
|
||||
},
|
||||
"RegisterRequest": {
|
||||
"properties": {
|
||||
"password": {
|
||||
"type": "string",
|
||||
"minLength": 6,
|
||||
"title": "Password",
|
||||
"description": "User password (minimum 6 characters). Stored only as a hash.",
|
||||
"examples": [
|
||||
"SuperSecure123"
|
||||
]
|
||||
},
|
||||
"username": {
|
||||
"type": "string",
|
||||
"maxLength": 50,
|
||||
"minLength": 3,
|
||||
"title": "Username",
|
||||
"description": "Unique username used for authentication and display",
|
||||
"examples": [
|
||||
"tester"
|
||||
]
|
||||
},
|
||||
"email": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"format": "email"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Email",
|
||||
"description": "Primary email address associated with the account",
|
||||
"examples": [
|
||||
"tester@example.com"
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"required": [
|
||||
"password",
|
||||
"username"
|
||||
],
|
||||
"title": "RegisterRequest",
|
||||
"description": "Payload for registering a new user account.\n\nThis model contains the minimum required identity and credential\ninformation to create a new user.\n\nFields:\n username: Unique username identifier.\n email: User's email address.\n password: Plain-text password (to be hashed by the repository layer).\n\nNotes:\n - Validation and normalization handled by mixins.\n - This model is never returned in responses.",
|
||||
"example": {
|
||||
"email": "tester@example.com",
|
||||
"password": "SuperSecure123",
|
||||
"username": "tester"
|
||||
}
|
||||
},
|
||||
"ValidationError": {
|
||||
"properties": {
|
||||
"loc": {
|
||||
"items": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "integer"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "array",
|
||||
"title": "Location"
|
||||
},
|
||||
"msg": {
|
||||
"type": "string",
|
||||
"title": "Message"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"title": "Error Type"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"required": [
|
||||
"loc",
|
||||
"msg",
|
||||
"type"
|
||||
],
|
||||
"title": "ValidationError"
|
||||
}
|
||||
},
|
||||
"securitySchemes": {
|
||||
"HTTPBearer": {
|
||||
"type": "http",
|
||||
"scheme": "bearer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
{
|
||||
"name": "Auth",
|
||||
"description": "Login, registration, token issuance, refresh, and identity operations."
|
||||
},
|
||||
{
|
||||
"name": "Health",
|
||||
"description": "Service health and diagnostics."
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -2,4 +2,6 @@ DEBUG=false
|
||||
MONGO_URI=mongodb://localhost:27017
|
||||
MONGO_DB=app_template
|
||||
WORKER_POLL_SECONDS=30
|
||||
WORKER_MAX_RETRIES=3
|
||||
WORKER_MAX_RETRIES=3
|
||||
AUTH_SERVER=http://localhost:8000
|
||||
JWT_SERVER=http://localhost:8000
|
||||
9
standards/mcp/templates/app/interfaces/auth/__init__.py
Normal file
9
standards/mcp/templates/app/interfaces/auth/__init__.py
Normal file
@@ -0,0 +1,9 @@
|
||||
"""# Summary
|
||||
|
||||
Auth interface: thin FastAPI entry points related to authentication, wired to
|
||||
openapi.yaml operationIds by the OpenAPI-first router.
|
||||
|
||||
Authentication itself is provided by the shared auth-server service. Wire it by
|
||||
declaring a ``bearerAuth`` security scheme in ``openapi.yaml`` (see
|
||||
``security.yaml``) and reading the contract at ``docs://spec``.
|
||||
"""
|
||||
14
standards/mcp/templates/app/interfaces/auth/security.yaml
Normal file
14
standards/mcp/templates/app/interfaces/auth/security.yaml
Normal file
@@ -0,0 +1,14 @@
|
||||
security:
|
||||
- bearerAuth: []
|
||||
components:
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
x-server-url: "{AUTH_SERVER}"
|
||||
x-introspect-path: "/introspect"
|
||||
x-login-path: "/login"
|
||||
x-register-path: "/register"
|
||||
x-logout-path: "/logout"
|
||||
x-me-path: "/me"
|
||||
Reference in New Issue
Block a user