# PHP SSO Service - AI Integration Context

> Tài liệu này dành cho AI khi hỗ trợ tích hợp **một ứng dụng bên ngoài**

## 1. Vai trò của hệ thống

PHP SSO Service là OAuth 2.0 / OpenID Connect Identity Provider. Ứng dụng cần
đăng nhập SSO được gọi là **client application** hoặc **relying party**.

Mục tiêu tích hợp:

- Người dùng bấm “Đăng nhập bằng SSO” trên client application.
- Client chuyển người dùng tới SSO để đăng nhập và cấp quyền.
- SSO trả client về callback URL bằng authorization code.
- Client đổi code lấy access token.
- Client dùng access token gọi UserInfo để lấy thông tin người dùng.
- Client tạo session nội bộ cho người dùng sau khi xác thực thành công.

## 2. Thông tin cần cung cấp trước khi tích hợp

AI cần hỏi người triển khai các thông tin sau nếu chưa có:

| Thông tin | Ví dụ |
| --- | --- |
| SSO base URL | `https://sso.example.com` |
| Client ID | Nhận từ Developer Dashboard |
| Client Secret | Chỉ dùng ở backend, không đưa vào frontend |
| Redirect URI | `https://app.example.com/auth/sso/callback` |
| Loại ứng dụng | Web server, SPA, mobile hoặc desktop |
| Ngôn ngữ/framework | PHP, Laravel, Node.js, Python, Java, .NET... |

`redirect_uri` phải khớp chính xác với URI đã đăng ký trong Developer
Dashboard, bao gồm scheme, hostname, port, path và dấu `/` cuối cùng.

## 3. Endpoint và contract

Thay `{SSO_BASE_URL}` bằng base URL thực tế của máy chủ SSO.

| Endpoint | Method | Dùng để |
| --- | --- | --- |
| `{SSO_BASE_URL}/authorize` | `GET` | Bắt đầu đăng nhập và xin authorization code |
| `{SSO_BASE_URL}/api/token` | `POST` | Đổi code thành access token |
| `{SSO_BASE_URL}/api/userinfo` | `GET` | Lấy thông tin người dùng |

### Authorization endpoint

Client redirect trình duyệt tới URL có các query parameter:

```text
{SSO_BASE_URL}/authorize
  ?response_type=code
  &client_id={CLIENT_ID}
  &redirect_uri={URL_ENCODED_REDIRECT_URI}
  &scope=openid%20profile%20email
  &state={RANDOM_STATE}
```

Client phải tạo và lưu `state` trước khi redirect. Khi callback quay về, phải
so sánh `state` nhận được với giá trị đã lưu; nếu khác thì từ chối request.

### Token endpoint

Với confidential web application:

```http
POST {SSO_BASE_URL}/api/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code={AUTHORIZATION_CODE}
&redirect_uri={REDIRECT_URI}
&client_id={CLIENT_ID}
&client_secret={CLIENT_SECRET}
```

Với SPA, mobile hoặc desktop app, dùng PKCE và gửi thêm:

```text
code_verifier={ORIGINAL_CODE_VERIFIER}
```

Không gửi `client_secret` vào JavaScript frontend, mobile bundle hoặc nơi người
dùng có thể trích xuất được.

### UserInfo endpoint

```http
GET {SSO_BASE_URL}/api/userinfo
Authorization: Bearer {ACCESS_TOKEN}
```

Client cần xử lý response theo JSON thực tế của môi trường SSO và dùng một
định danh ổn định (ví dụ `sub` hoặc `id`) để liên kết với user nội bộ. Không
dùng email làm định danh duy nhất nếu nghiệp vụ yêu cầu email có thể thay đổi.

## 4. Luồng tích hợp chuẩn

1. Đăng ký client trong Developer Dashboard.
2. Cấu hình chính xác `client_id`, secret và callback URL trong biến môi trường
   của client application.
3. Tạo `state` ngẫu nhiên cho từng lần đăng nhập.
4. Với public client, tạo `code_verifier` và `code_challenge` theo S256.
5. Redirect người dùng tới `/authorize`.
6. Tại callback, kiểm tra `state` và đọc `code`.
7. Gửi server-to-server request tới `/api/token`.
8. Gọi `/api/userinfo` bằng access token.
9. Tạo session nội bộ và redirect người dùng về trang ban đầu.
10. Xóa authorization code, state và verifier tạm thời sau khi dùng.

## 5. Quy tắc bảo mật bắt buộc

- Chỉ dùng HTTPS ở production.
- Dùng PKCE cho SPA, mobile và desktop.
- Dùng `state` để chống CSRF.
- Lưu client secret trong secret manager hoặc environment variable.
- Không commit secret vào Git, không log token và không hiển thị token trên URL.
- Chỉ cho phép callback URL đã đăng ký; không chấp nhận redirect URL tùy ý từ
  query string.
- Xác thực lỗi token và lỗi UserInfo rõ ràng; không tạo session nếu bước nào
  thất bại.
- Access token và refresh token phải được bảo vệ như mật khẩu.

## 6. Hướng dẫn cho AI khi implement

Khi người dùng yêu cầu tích hợp SSO vào một dự án:

1. Xác định framework, entry point đăng nhập, callback route và session system
   của **client application**.
2. Không sửa source code hoặc database của PHP SSO Service trừ khi người dùng
   yêu cầu rõ ràng.
3. Tái sử dụng OAuth/OIDC library phù hợp với ngôn ngữ/framework nếu có.
4. Giữ secret ở backend và dùng biến môi trường.
5. Tạo thay đổi tối thiểu gồm: login route, callback route, token exchange,
   UserInfo request, session creation, logout handling và error handling.
6. Bổ sung cấu hình `.env.example`, không ghi secret thật.
7. Kiểm thử cả success flow, sai state, sai callback URL, code hết hạn và token
   bị từ chối.

## 7. Prompt khởi đầu đề xuất

```text
Hãy tích hợp ứng dụng hiện tại với PHP SSO Service theo OAuth 2.0
Authorization Code Flow và OpenID Connect. Đọc docs/AI-CONTEXT.md trước.
Đây là tài liệu tích hợp client application, không phải yêu cầu sửa source
code của SSO Service.

Hãy kiểm tra framework và cơ chế session hiện tại, sau đó triển khai login
route, callback route, state validation, PKCE nếu là public client, token
exchange, UserInfo request và tạo session nội bộ. Dùng biến môi trường cho
SSO_BASE_URL, CLIENT_ID, CLIENT_SECRET và REDIRECT_URI. Không commit secret,
không log token, không thay đổi OAuth contract, và bổ sung hướng dẫn cấu hình
và kiểm thử.
```
