Files
openmonetis/app/api/auth/device/tokens/route.ts
Felipe Coutinho 2532f2d6ad feat(auth): add API token authentication for OpenSheets Companion
- Implement JWT-based authentication system for device access
  - Access tokens (7 day expiry) and refresh tokens (90 day expiry)
  - HMAC-SHA256 signing with timing-safe comparison
  - Token hashing with SHA-256 for secure storage

- Add device authentication endpoints:
  - POST /api/auth/device/token - Login with email/password, get tokens
  - POST /api/auth/device/refresh - Refresh access token
  - POST /api/auth/device/verify - Verify token validity
  - GET /api/auth/device/tokens - List user's API tokens
  - DELETE /api/auth/device/tokens/[id] - Revoke specific token

- Track token usage (last used timestamp and IP)
2026-01-23 12:11:19 +00:00

54 lines
1.5 KiB
TypeScript

/**
* GET /api/auth/device/tokens
*
* Lista todos os tokens de API do usuário.
* Requer sessão web autenticada.
*/
import { auth } from "@/lib/auth/config";
import { db } from "@/lib/db";
import { apiTokens } from "@/db/schema";
import { eq, desc } from "drizzle-orm";
import { headers } from "next/headers";
import { NextResponse } from "next/server";
export async function GET() {
try {
// Verificar autenticação via sessão web
const session = await auth.api.getSession({ headers: await headers() });
if (!session?.user) {
return NextResponse.json(
{ error: "Não autenticado" },
{ status: 401 }
);
}
// Buscar tokens ativos do usuário
const tokens = await db
.select({
id: apiTokens.id,
name: apiTokens.name,
tokenPrefix: apiTokens.tokenPrefix,
lastUsedAt: apiTokens.lastUsedAt,
lastUsedIp: apiTokens.lastUsedIp,
expiresAt: apiTokens.expiresAt,
createdAt: apiTokens.createdAt,
})
.from(apiTokens)
.where(eq(apiTokens.userId, session.user.id))
.orderBy(desc(apiTokens.createdAt));
// Separar tokens ativos e revogados
const activeTokens = tokens.filter((t) => !t.expiresAt || new Date(t.expiresAt) > new Date());
return NextResponse.json({ tokens: activeTokens });
} catch (error) {
console.error("[API] Error listing device tokens:", error);
return NextResponse.json(
{ error: "Erro ao listar tokens" },
{ status: 500 }
);
}
}