สารบัญ

ต่อระบบ

Permission manifest

ประกาศสิ่งที่แอปอนุญาตได้ ส่งเทมเพลต role และ sync จากคอนโซลหรือ pipeline deploy

manifest คือวิธีที่แอปบอก Pi Auth ว่าในแอปมีอะไรให้อนุญาตได้บ้าง permission เป็นข้อความธรรมดาที่แอปตรวจเอง ส่วนเทมเพลต role ให้องค์กรมีจุดเริ่มที่สมเหตุสมผล sync ทุกครั้งที่ permission ของแอปเปลี่ยน — ปกติทำตอน deploy

โครงของ manifest

manifest.json
{
  "application": "AOWrBtppsYLxThsohmXWS7JjCknWiog9",
  "name": "Pi PDF",
  "permissions": [
    { "key": "pdf:use",   "name": "ใช้งาน Pi PDF",   "risk": "LOW" },
    { "key": "pdf:admin", "name": "ดูแล Pi PDF", "description": "จัดการเทมเพลตและการตั้งค่า", "risk": "HIGH" }
  ],
  "roleTemplates": [
    { "key": "pdf-user",  "name": "ผู้ใช้ Pi PDF",  "permissions": ["pdf:use"] },
    { "key": "pdf-admin", "name": "ผู้ดูแล Pi PDF", "permissions": ["pdf:use", "pdf:admin"] }
  ]
}
ฟิลด์กติกา
applicationตัวกันพลาด (ไม่บังคับ): ใส่ได้เฉพาะเมื่อตรงกับ client_id (หรือ softwareId) ของแอปที่ sync — ไม่ตรงจะถูกปฏิเสธ 400; แอปที่มีหลาย client เช่น dev/prod ให้ละไว้
permissions[].keyรูปแบบ app:action ตัวพิมพ์เล็ก ต่อท้ายด้วยจุดได้ — เช่น memo:approve, memo:report.export ยาว 3–64 ตัวอักษร สูงสุด 500 รายการต่อแอป
permissions[].name / descriptionแสดงให้ผู้ดูแลเห็นในคอนโซลตอนสร้าง role
permissions[].riskLOW (ค่าเริ่มต้น) หรือ HIGH — สิทธิ์ HIGH ถูกเน้นในคอนโซลให้ผู้ดูแลสังเกตเมื่อ role ให้สิทธิ์นั้น
roleTemplates[]role แนะนำ เมื่อองค์กรติดตั้งแอปจะได้ role สำเร็จรูปเหล่านี้ไว้ผูกหรือแก้ต่อ

ประกาศ permission ครั้งเดียว แล้วให้ Pi Auth ดึง

ประกาศ permission ครั้งเดียวในโค้ด ได้ทั้ง key แบบ type-safe และ manifest สำหรับ Pi Auth ไม่ต้องแก้ไฟล์ JSON ซ้ำหรือสร้าง cron เพื่อ sync

lib/permissions.ts
import { definePermissions } from "@suphark/auth-client/manifest";

export const P = definePermissions(
  {
    "memo:create":  { name: "สร้างเอกสาร" },
    "memo:approve": { name: "ลงนามอนุมัติ", risk: "HIGH" },
  },
  {
    roleTemplates: { "memo-approver": { name: "ผู้อนุมัติ", permissions: ["memo:create", "memo:approve"] } },
    autoApplyTemplates: true, // องค์กรที่ติดตั้งได้ role จากเทมเพลตทันที
  },
);

// ในโค้ด — key พิมพ์ผิดเป็น type error
piAuth.hasPermission(user, P.keys["memo:approve"]);
lib/pi-auth.ts (Next.js)
import { createPiAuth } from "@suphark/auth-client/next";
import { P } from "./permissions";

export const piAuth = createPiAuth({
  manifest: P.manifest, // หรือส่ง P ตรงๆ
  // ...
});

// ใน app/auth/[...pi]/route.ts
// export const { GET, POST } = piAuth.handlers;
// Route GET /auth/manifest จะเปิดให้อัตโนมัติ ไม่ต้องสร้าง route แยก

ถ้าแอปมี proxy บังคับล็อกอิน ให้เพิ่ม /auth/manifest ใน public paths เพื่อให้ endpoint คืน JSON โดยไม่ redirect ไปหน้าเข้าสู่ระบบ

ลงทะเบียนแอปใน Pi Auth เลือก “มี permission แล้ว” ใส่ base URL ของแอป เช่นhttps://app.example.com แล้วกด “ทดสอบและ Sync” Pi Auth จะดึง JSON จาก/auth/manifest เมื่อ permission เปลี่ยนให้กลับมากด Sync อีกครั้ง แอปที่ยังไม่มี permission เลือก “เพิ่มภายหลัง” ได้

แอปแบบ confidential ยัง Push manifest ชุดเดียวกันด้วย client_id และ client_secret ไปที่POST /api/apps/manifest หลัง deploy ได้ แอปแบบ public ใช้ Pull ทั้งสองทางไม่ต้องส่ง heartbeat รายวัน Pi Auth อัปเดตเวลาการใช้งานผ่าน OIDC token traffic ให้อัตโนมัติ

ประกาศ webhook ในโค้ด · ตรวจสิทธิ์แบบ type-safe · เริ่มโปรเจกต์ใหม่

lib/permissions.ts (เพิ่มเติม)
export const P = definePermissions({ ... }, {
  // Pi Auth ลงทะเบียน webhook endpoint ให้ทุกองค์กรที่ติดตั้งแอป (path ต่อท้าย APP_URL) — ตรวจลายเซ็น JWS ไม่ต้องมี secret
  webhook: { path: "/api/pi-auth/webhook", events: ["membership.created", "membership.left", "role.binding.changed"] },
});

// ตรวจสิทธิ์ด้วย key ชุดเดียวกันทั้ง server และ client component
P.can(await piAuth.getCurrentUser(), "memo:approve");   // server
P.can(useUser().user, "memo:approve");                   // client ("memo:aprove" = type error)

แอปใหม่: npx pi-auth init สร้าง lib/pi-auth.ts, lib/permissions.ts, app/auth/[...pi]/route.ts, app/api/pi-auth/webhook/route.ts, proxy.ts และเติม .env.example ให้ (ไม่ทับไฟล์เดิม เว้นแต่ใส่ --force) proxy ที่สร้างให้เปิดทางสาธารณะไปยัง /auth/manifest ด้วย

ทางอื่นในการ sync

  1. จากคอนโซล (App setup)

    platform admin เปิด Platform → Applications → ตั้งค่า → Permissionใส่ base URL แล้วกด “ทดสอบและ Sync” Pi Auth ตรวจ manifest และแสดงผลที่เปลี่ยน เจ้าของแอปทำแบบเดียวกันจากหน้า Access ของแอปได้

  2. ตอน build (ไม่ต้องกดปุ่ม)

    แอปที่เก็บ manifest เป็นไฟล์ pi-auth.manifest.json ใส่ CLI ของ SDK ไว้ก่อน build ทุกครั้งที่ deploy สิทธิ์ใน Pi Auth จะตรงกับโค้ดเอง (ใช้ client id/secret ของแอป ไม่ต้องมี service account)

    package.json
    "scripts": {
      "prebuild": "pi-auth manifest sync --optional"
    }

    --optional (SDK 0.8.3+): ไม่มี env PI_AUTH_* (เช่น build preview) หรือ Pi Auth ไม่ตอบ = เตือนแล้ว build ต่อ; manifest ผิดรูปแบบยังทำให้ build ล้ม

  3. จาก pipeline deploy

    สร้าง service account ของแอปที่มี scope application.manifest แล้ว POST manifest ด้วย service token ของมัน:

    POST /api/v1/applications/{clientId}/manifest
    curl -X POST https://auth.suphark.com/api/v1/applications/$CLIENT_ID/manifest \
      -H "Authorization: Bearer $SERVICE_TOKEN" \
      -H "Content-Type: application/json" \
      --data @manifest.json

sync แล้วเกิดอะไร

  • key ใหม่ถูกเพิ่ม; ชื่อ คำอธิบาย และ risk ถูกอัปเดตในที่
  • key ที่หายไปจาก manifest ใหม่ถูกทำเครื่องหมาย deprecated ไม่ได้ลบ: role เดิมยังใช้ได้ คอนโซลแสดงขีดฆ่า และ role ใหม่เลือกไม่ได้ เอาออกจาก role แล้วมันจะหายจากโทเค็น
  • เทมเพลต role ถูกอัปเดต; role ที่องค์กรสร้างจากเทมเพลตไปแล้วไม่ถูกแตะ

ติดตั้งในองค์กร

ผู้ดูแล tenant เปิด สิทธิ์ → แอปที่ติดตั้ง แล้วติดตั้งแอป จากนั้น permission ของแอปจะปรากฏตอนสร้าง role เทมเพลตพร้อมใช้ และสมาชิกล็อกอินเข้าแอปได้ ถอนการติดตั้งแล้วทั้งสองอย่างหยุด: role เสีย permission ของแอปนั้น และการล็อกอินถูกปฏิเสธ