| name | api-auth-guard |
| description | Use this skill BEFORE creating, editing, or reviewing any file in src/app/api/**/route.ts in the SmartHouse project. Invoke when the task mentions API route, endpoint, backend, /api/, route.ts, NextRequest, middleware, authentication, auth, autoryzacja, token, cron, CRON_SECRET, session, iron-session. This skill enforces that EVERY endpoint has one of three auth mechanisms (iron-session, CRON_SECRET Bearer, or Firebase ID token) before returning data. |
API Auth Guard — Obowiązkowa weryfikacja autoryzacji
Kontekst
Reguła #4 ("Każde API route wymaga auth") w CLAUDE.md i AGENTS.md. Brak autoryzacji = bezpośrednie ryzyko wycieku danych mieszkańców i pracowników.
SmartHouse używa trzech mechanizmów autoryzacji — każdy endpoint musi mieć dokładnie jeden.
Trzy dozwolone wzorce auth
Wzorzec A — iron-session (endpointy UI wywoływane z przeglądarki)
import { getSession } from '@/lib/auth';
export async function GET(req: NextRequest) {
const session = await getSession();
if (!session?.uid) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
if (!session.isAdmin) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
}
Kiedy używać: endpointy wywoływane przez fetch z komponentów React, operacje powiązane z konkretnym użytkownikiem.
Przykłady w projekcie: src/app/api/employees/stats/route.ts, src/app/api/control-cards/route.ts
Wzorzec B — CRON_SECRET Bearer (cron joby, manualne egzekucje przez admin proxy)
function authorize(req: NextRequest): boolean {
const authHeader = req.headers.get('authorization');
return !!process.env.CRON_SECRET && authHeader === `Bearer ${process.env.CRON_SECRET}`;
}
export async function POST(req: NextRequest) {
if (!authorize(req)) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
}
Kiedy używać: Firebase Scheduler, alert cron, data-guard, wszelkie automatyczne wywołania.
Przykład w projekcie: src/app/api/alerts/route.ts:7-11
Wzorzec C — Admin Proxy (cron wywoływany ręcznie przez admina z UI)
Endpoint admin proxy weryfikuje getSession().isAdmin, a następnie wewnętrznie fetchuje chroniony endpoint cron z CRON_SECRET. Nigdy nie ujawniaj CRON_SECRET klientowi.
Checklist dla każdego nowego route
Wykonaj zanim napiszesz logikę biznesową:
Antywzorce — natychmiastowy bloker
Jeśli zobaczysz w kodzie któryś z poniższych — zatrzymaj się i zgłoś:
export async function GET(req: NextRequest) {
const data = await getEmployees();
return NextResponse.json(data);
}
export async function POST() { ... }
if (req.headers.get('x-my-custom-token') === 'hardcoded-value') { ... }
const SECRET = 'super-secret-123';
return NextResponse.json({ error: err.stack }, { status: 500 });
Rate limiting (dla krytycznych endpointów)
Dla endpointów wykonujących drogie operacje (wysyłka push, pisanie do Sheets, cron) rozważ dodanie rate limiting. Na ten moment w projekcie nie ma dedykowanej biblioteki — zaproponuj orchestratorowi dyskusję zanim dodasz.
Środowiskowe — sekrety
Sekret używany w auth (np. CRON_SECRET) musi być:
- W
.env.local (dev)
- W
apphosting.yaml jako sekret
- Ustawiony przez
firebase apphosting:secrets:set
Brak któregokolwiek z trzech miejsc = awaria na produkcji. Szczegóły w feedback_secrets_both_places.
Output dla Orchestratora
API_AUTH_AUDIT:
files_audited:
- src/app/api/employees/route.ts: ✅ pattern A (iron-session + isAdmin)
- src/app/api/alerts/run/route.ts: ✅ pattern B (CRON_SECRET)
- src/app/api/public/something/route.ts: ❌ NO AUTH — BLOCKER
status: blocked_on_missing_auth | all_green
action_required: Add auth to src/app/api/public/something/route.ts