2026-10-26 06:29:19 +07:00
|
|
|
// PLAN-DOCVER.md §auth — POST /api/documents/token ออก access_token ของกลุ่ม docver
|
|
|
|
|
// ยืนยันด้วย header "x-api-key" เทียบ env DOCVER_API_KEY (fail closed เมื่อ env ไม่
|
|
|
|
|
// ตั้ง/ว่าง) — token เป็น JWT HS256 เซ็นด้วย env DOCVER_TOKEN_SECRET อายุตาม env
|
|
|
|
|
// DOCVER_TOKEN_TTL_SECONDS (default 3600) แล้วนำไปแนบ Authorization: Bearer กับ
|
|
|
|
|
// endpoint อื่นของกลุ่ม (lib/docver-token.ts) · segment คงที่ "token" ไม่ชน [docId]
|
|
|
|
|
// (Next ให้ static ชนะ) และ middleware ยกเว้น api/documents/* อยู่แล้ว
|
|
|
|
|
import { docverError } from "@/lib/document-versioning";
|
|
|
|
|
import {
|
|
|
|
|
issueDocverToken,
|
|
|
|
|
parseTokenRequestBody,
|
|
|
|
|
requireDocverApiKey,
|
|
|
|
|
} from "@/lib/docver-token";
|
|
|
|
|
|
|
|
|
|
export const runtime = "nodejs";
|
|
|
|
|
export const dynamic = "force-dynamic";
|
|
|
|
|
|
|
|
|
|
export async function POST(request: Request) {
|
|
|
|
|
const apiKeyFail = requireDocverApiKey(request);
|
|
|
|
|
if (apiKeyFail !== null) return apiKeyFail;
|
|
|
|
|
|
|
|
|
|
let raw: unknown;
|
|
|
|
|
try {
|
|
|
|
|
raw = await request.json();
|
|
|
|
|
} catch {
|
|
|
|
|
return docverError("body ต้องเป็น JSON", 400);
|
|
|
|
|
}
|
|
|
|
|
const parsed = parseTokenRequestBody(raw);
|
|
|
|
|
if (!parsed.ok) return docverError(parsed.error, 400);
|
|
|
|
|
|
|
|
|
|
// ความผิด config ฝั่ง server ไม่ใช่ความผิดของผู้เรียก — ไม่ตั้ง = 500 (ห้าม log ค่า secret)
|
2026-10-26 18:37:02 +07:00
|
|
|
const secret = process.env.DOCVER_TOKEN_SECRET?.trim();
|
|
|
|
|
// const secret =
|
|
|
|
|
// "487023dd1c1c4d6a07475e96b1cc300fec1e68ac9c2dd7d5ac9b1bf75da1053e";
|
2026-10-26 12:37:29 +07:00
|
|
|
|
2026-10-26 18:37:02 +07:00
|
|
|
if (secret === undefined || secret === "") {
|
|
|
|
|
return docverError("DOCVER_TOKEN_SECRET ยังไม่ถูกตั้งค่า", 500);
|
|
|
|
|
}
|
2026-10-26 06:29:19 +07:00
|
|
|
const ttlRaw = Number(process.env.DOCVER_TOKEN_TTL_SECONDS);
|
2026-10-26 12:37:29 +07:00
|
|
|
const ttlSeconds =
|
|
|
|
|
Number.isFinite(ttlRaw) && ttlRaw > 0 ? Math.floor(ttlRaw) : 3600;
|
2026-10-26 06:29:19 +07:00
|
|
|
|
|
|
|
|
const accessToken = issueDocverToken(parsed.claims, secret, ttlSeconds);
|
|
|
|
|
return new Response(
|
|
|
|
|
JSON.stringify({
|
|
|
|
|
access_token: accessToken,
|
|
|
|
|
token_type: "Bearer",
|
|
|
|
|
expires_in: ttlSeconds,
|
|
|
|
|
}),
|
|
|
|
|
{ headers: { "content-type": "application/json; charset=utf-8" } },
|
|
|
|
|
);
|
|
|
|
|
}
|