Files
pocketpaw/docs/api/get-qr-code.mdx
Ragini Pandey ee64be4fc8 fix(security): require auth on /api/qr to prevent session token leak
Remove /api/qr and /api/v1/qr from exempt_paths in auth middleware so
the QR endpoint can no longer be hit without a valid session. Previously
any network-reachable client could GET /api/qr, decode the PNG, and
extract a fully valid 1-hour session token — a complete auth bypass
(OWASP A01 — Broken Access Control).

Changes:
- Remove /api/qr and /api/v1/qr from exempt_paths in dashboard_auth.py
- Reduce QR pairing token TTL from 1 hour to 60 seconds
- Add ttl_seconds param to create_session_token() for short-lived tokens
- Add audit log event on QR code generation
- Update v1 QR endpoint (/api/v1/auth.py) with matching fix
- Update tests: unauthenticated /api/qr now returns 401
- Update docs to reflect auth requirement

Fixes #854
2026-04-03 19:52:32 +00:00

68 lines
2.0 KiB
Plaintext

---
title: Generate QR Login Code
description: "Generate a QR code for mobile device login to the PocketPaw dashboard. Scan the QR code with your phone to authenticate without manually entering credentials or tokens."
api: GET /api/qr
baseUrl: http://localhost:8000
layout: '@/layouts/APIEndpointLayout.astro'
auth: bearer
section: API Reference
ogType: article
keywords: ["qr code login", "mobile auth", "qr authentication"]
tags: ["api", "authentication"]
---
## Overview
Generates a QR code PNG image that encodes the dashboard URL with an embedded access token. Scanning this QR code on a mobile device automatically authenticates the user.
This endpoint **requires authentication**. The caller must already have a valid session (via Bearer token, session cookie, or localhost bypass). The QR code embeds a short-lived (60-second) pairing token so that a leaked QR image cannot grant long-lived access.
## Response
Returns a PNG image (`image/png` content type) as a streaming response.
<RequestExample>
<Tabs items={["cURL", "JavaScript", "Python"]}>
<Tab title="cURL">
```bash
curl -X GET "http://localhost:8000/api/qr" \
-H "Authorization: Bearer $TOKEN" -o login-qr.png
```
</Tab>
<Tab title="JavaScript">
```javascript
const response = await fetch("http://localhost:8000/api/qr", {
headers: { Authorization: `Bearer ${token}` },
});
const blob = await response.blob();
const url = URL.createObjectURL(blob);
// Use url in an <img> tag or download link
console.log("QR code blob URL:", url);
```
</Tab>
<Tab title="Python">
```python
import requests
response = requests.get(
"http://localhost:8000/api/qr",
headers={"Authorization": f"Bearer {token}"},
)
with open("login-qr.png", "wb") as f:
f.write(response.content)
print("QR code saved to login-qr.png")
```
</Tab>
</Tabs>
</RequestExample>
<ResponseExample>
<Tabs items={["200"]}>
<Tab title="200">
```
Binary PNG image (content-type: image/png)
```
</Tab>
</Tabs>
</ResponseExample>