diff --git a/API.md b/API.md index 1b42355..e6511ad 100644 --- a/API.md +++ b/API.md @@ -41,7 +41,6 @@ Notes: | GET | `/auth/` | `/` | Main authentication SPA (non-auth hosts show an account summary view) | | GET | `/auth/admin/` | `/admin/` | Admin SPA root | | GET | `/auth/{reset_token}` | `/{reset_token}` | Reset / device addition SPA (token validated) | -| GET | `/auth/restricted` | `/restricted` | Restricted / permission denied SPA | ## Core API (Unrestricted – available on all hosts) @@ -49,6 +48,8 @@ Always under `/auth/api/` (even on auth host): | Method | Path | Description | |--------|------|-------------| +| GET | `/auth/api/restricted` | Authentication UI for iframe embedding (supports `?mode=login` or `?mode=reauth`) | +|--------|------|-------------| | POST | `/auth/api/validate` | Validate & (conditionally) renew session | | GET | `/auth/api/forward` | Auth proxy endpoint for reverse proxies (204 or 4xx) | | POST | `/auth/api/set-session` | Set cookie from Bearer token | diff --git a/examples/restricted-api.html b/examples/restricted-api.html index 9a5494f..c00096a 100644 --- a/examples/restricted-api.html +++ b/examples/restricted-api.html @@ -111,7 +111,7 @@ iframe.title = 'Authentication'; document.body.appendChild(iframe); } - iframe.src = '/auth/restricted-api/?mode=login'; + iframe.src = '/auth/api/restricted?mode=login'; showStatus('Login mode loaded - for users who are not authenticated', 'info'); } @@ -123,7 +123,7 @@ iframe.title = 'Authentication'; document.body.appendChild(iframe); } - iframe.src = '/auth/restricted-api/?mode=reauth'; + iframe.src = '/auth/api/restricted?mode=reauth'; showStatus('Reauth mode loaded - for additional verification of authenticated users', 'info'); } @@ -133,7 +133,7 @@ iframe = document.createElement('iframe'); iframe.id = 'auth-iframe'; iframe.title = 'Authentication'; - iframe.src = '/auth/restricted-api'; + iframe.src = '/auth/api/restricted'; document.body.appendChild(iframe); iframeInitialized = true; } diff --git a/frontend/src/App.vue b/frontend/src/App.vue index b9f6493..9ba28fe 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -57,7 +57,7 @@ function showAuthIframe() { authIframe = document.createElement('iframe') authIframe.id = 'auth-iframe' authIframe.title = 'Authentication' - authIframe.src = '/auth/restricted-api/?mode=login' + authIframe.src = '/auth/api/restricted?mode=login' document.body.appendChild(authIframe) loadingMessage.value = 'Authentication required...' } diff --git a/frontend/src/admin/AdminApp.vue b/frontend/src/admin/AdminApp.vue index 70980fb..020794a 100644 --- a/frontend/src/admin/AdminApp.vue +++ b/frontend/src/admin/AdminApp.vue @@ -330,7 +330,7 @@ function showAuthIframe() { authIframe = document.createElement('iframe') authIframe.id = 'auth-iframe' authIframe.title = 'Authentication' - authIframe.src = '/auth/restricted-api/?mode=login' + authIframe.src = '/auth/api/restricted?mode=login' document.body.appendChild(authIframe) loadingMessage.value = 'Authentication required...' } diff --git a/passkey/fastapi/api.py b/passkey/fastapi/api.py index bd1b7aa..ce844f1 100644 --- a/passkey/fastapi/api.py +++ b/passkey/fastapi/api.py @@ -10,7 +10,7 @@ from fastapi import ( Request, Response, ) -from fastapi.responses import JSONResponse +from fastapi.responses import FileResponse, JSONResponse from fastapi.security import HTTPBearer from passkey.util import frontend @@ -36,6 +36,12 @@ app = FastAPI() app.mount("/user", user.app) +@app.get("/restricted") +async def restricted_view(): + """Serve the restricted/authentication UI for iframe embedding.""" + return FileResponse(frontend.file("restricted-api", "index.html")) + + @app.exception_handler(HTTPException) async def http_exception_handler(_request: Request, exc: HTTPException): """Ensure auth cookie is cleared on 401 responses (JSON responses only).""" diff --git a/passkey/fastapi/mainapp.py b/passkey/fastapi/mainapp.py index bb03c4e..a6f888e 100644 --- a/passkey/fastapi/mainapp.py +++ b/passkey/fastapi/mainapp.py @@ -89,16 +89,6 @@ async def admin_root(request: Request, auth=AUTH_COOKIE): return await admin.adminapp(request, auth) # Delegated to admin app -@app.get("/auth/restricted") -async def restricted_view(): - return FileResponse(frontend.file("restricted", "index.html")) - - -@app.get("/auth/restricted-api") -async def restricted_api_view(): - return FileResponse(frontend.file("restricted-api", "index.html")) - - # Note: this catch-all handler must be the last route defined @app.get("/{reset}") @app.get("/auth/{reset}")