# OAuth (/developer/oauth)

ให้ผู้ใช้ EasyDonate เชื่อมต่อบัญชีกับแอปของคุณ - Authorization Code + PKCE



OAuth 2.0 ให้แอปหรือแพลตฟอร์มของคุณทำงานแทนผู้ใช้ EasyDonate คนอื่นได้
โดยผู้ใช้กดปุ่ม "เชื่อมต่อ EasyDonate" แล้วยินยอมสิทธิ์แบบ scope ด้วยตัวเอง -
ไม่ต้องแลกรหัสผ่านหรือ API key กัน

Flow เป็นแบบ Authorization Code + PKCE (บังคับใช้ PKCE ทุกกรณี)

## ลงทะเบียน application [#ลงทะเบียน-application]

ไปที่ <NavPath href="https://easydonate.app/dashboard/developer?tab=application" items="['หน้าจัดการ', 'โซนผู้พัฒนา', 'Applications']" /> สร้าง application
เพื่อรับ `client_id` และ `client_secret` พร้อมตั้งค่า `redirect_uri`

<Callout type="warn">
  `client_secret` ต้องอยู่ฝั่ง backend เท่านั้น - อย่าฝังในโค้ดฝั่ง browser
  หรือแอปที่แจกให้ผู้ใช้
</Callout>

## ขั้นตอนทั้งหมด [#ขั้นตอนทั้งหมด]

### 1. พาผู้ใช้ไปหน้ายืนยันสิทธิ์ [#1-พาผู้ใช้ไปหน้ายืนยันสิทธิ์]

```
https://easydonate.app/oauth/authorize?client_id=<client_id>
  &redirect_uri=<your_callback>
  &scope=read:profile read:donations
  &state=<random>
  &code_challenge=<S256_challenge>
  &code_challenge_method=S256
```

### 2. รับ code ที่ callback ของคุณ [#2-รับ-code-ที่-callback-ของคุณ]

ผู้ใช้เข้าสู่ระบบและกดยินยอม จากนั้น EasyDonate จะ redirect ไปที่
`redirect_uri?code=<code>&state=<state>` - ตรวจว่า `state` ตรงกับค่าที่คุณ
สร้างไว้ในขั้นตอนที่ 1 ก่อนไปต่อ

### 3. แลก code เป็น token จากฝั่ง backend ของคุณ [#3-แลก-code-เป็น-token-จากฝั่ง-backend-ของคุณ]

<Playground path="/oauth/token" method="post" />

Response:

```json
{
  "access_token": "<jwt>",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "ezdn_v1_rt_...",
  "scope": "read:profile read:donations"
}
```

`access_token` เป็น JWT ที่ถูกเซ็นแล้ว - ใส่ใน header `Authorization` ได้ตรง ๆ
ส่วน `refresh_token` เป็น opaque string ขึ้นต้นด้วย `ezdn_v1_rt_`

### 4. เรียก API ด้วย access token [#4-เรียก-api-ด้วย-access-token]

<Playground path="/api/v1/me" method="get" />

### 5. Refresh เมื่อหมดอายุ [#5-refresh-เมื่อหมดอายุ]

refresh token จะหมุนเวียนทุกครั้งที่ใช้ - เก็บตัวใหม่เสมอ

<Playground path="/oauth/token" method="post" />

### 6. เพิกถอน token (หรือถอดการเชื่อมต่อ) [#6-เพิกถอน-token-หรือถอดการเชื่อมต่อ]

<Playground path="/oauth/revoke" method="post" />

## อายุของ token [#อายุของ-token]

Access token มีอายุ 1 ชั่วโมง ส่วน refresh token มีอายุ 30 วัน โดย access token
เป็น stateless JWT จึงเพิกถอนรายตัวไม่ได้ - หากต้องการตัดสิทธิ์แอปให้เพิกถอน
refresh token (หรือถอดการเชื่อมต่อ) แทน

## ลิมิตแอปที่ยังไม่ผ่านการยืนยัน [#ลิมิตแอปที่ยังไม่ผ่านการยืนยัน]

แอปที่ยังไม่ผ่านการยืนยัน (unverified) เชื่อมต่อผู้ใช้ได้สูงสุด 20 คน -
ขอ verification ในหน้าจัดการเพื่อปลดลิมิต

## เช็กลิสต์ความปลอดภัย [#เช็กลิสต์ความปลอดภัย]

* ตรวจ `state` ที่ callback ทุกครั้งก่อนแลก code
* สร้าง `code_verifier` ใหม่ทุกรอบการขอสิทธิ์ และเก็บไว้ฝั่ง server
* เก็บ `refresh_token` ตัวใหม่ทุกครั้งหลัง refresh - ตัวเก่าจะใช้ไม่ได้ทันที
* ขอเฉพาะ scope ที่จำเป็น (ดู [Scopes](/developer/scopes))
