Authentication Endpoints
docsfy supports two authentication mechanisms:
- Bearer API key (recommended for API clients)
- Session cookie (
docsfy_session, used by browser login flow)
All routes are protected by middleware except /login, /login/, and /health.
```108:115:src/docsfy/main.py
Paths that do not require authentication
_PUBLIC_PATHS = frozenset({"/login", "/login/", "/health"})
async def dispatch( self, request: Request, call_next: RequestResponseEndpoint ) -> Response: if request.url.path in self._PUBLIC_PATHS: return await call_next(request)
## Endpoint Reference
| Endpoint | Method | Auth Required | Purpose | Success Behavior |
|---|---|---|---|---|
| `/login` | `GET` | No | Render login page | `200` HTML |
| `/login` | `POST` | No | Authenticate username + API key, create session | `302` redirect to `/`, sets `docsfy_session` cookie |
| `/logout` | `GET` | Yes | Invalidate session and clear cookie | `302` redirect to `/login`, deletes `docsfy_session` cookie |
| `/health` | `GET` | No | Liveness endpoint | `200` JSON |
> **Tip:** For programmatic clients, use `/api/*` routes. Unauthenticated API calls return JSON `401`, while non-API paths redirect to `/login`.
```151:155:src/docsfy/main.py
if not user and not is_admin:
# Not authenticated
if request.url.path.startswith("/api/"):
return JSONResponse(status_code=401, content={"detail": "Unauthorized"})
return RedirectResponse(url="/login", status_code=302)
POST /login Details
POST /login reads form fields (not JSON): username and api_key.
```157:167:src/docsfy/templates/login.html