# Hướng Dẫn Xác Thực IAM Service > Hướng dẫn đầy đủ về xác thực sử dụng GoodGo IAM Service với OAuth2/OpenID Connect. ## Tổng Quan IAM Service cung cấp xác thực OAuth2/OIDC sử dụng Duende IdentityServer: - **Password Grant** - Đăng nhập user với email/password - **Refresh Token** - Làm mới token mà không cần xác thực lại - **Client Credentials** - Xác thực service-to-service - **Email Verification** - Xác minh email qua SMTP - **Two-Factor Authentication (2FA)** - TOTP với QR code và recovery codes - **Social Login** - Tích hợp OAuth Google và Facebook ## Bắt Đầu Nhanh ### 1. Đăng Ký User ```bash curl -X POST http://localhost:5001/api/v1/auth/register \ -H "Content-Type: application/json" \ -d '{ "email": "user@example.com", "password": "Password123!", "firstName": "John", "lastName": "Doe" }' ``` ### 2. Đăng Nhập (Lấy Tokens) ```bash curl -X POST http://localhost:5001/connect/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=password" \ -d "username=user@example.com" \ -d "password=Password123!" \ -d "scope=openid profile email offline_access" ``` **Response:** ```json { "access_token": "eyJhbGciOiJSUzI1NiIs...", "token_type": "Bearer", "expires_in": 900, "refresh_token": "eyJhbGciOiJSUzI1NiIs...", "scope": "openid profile email offline_access" } ``` ### 3. Sử Dụng Access Token ```bash curl http://localhost:5001/api/v1/users/me \ -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..." ``` ## Các Loại OAuth2 Grant ### Password Grant (Đăng Nhập User) Cho các ứng dụng đáng tin cậy nơi users nhập thông tin đăng nhập trực tiếp. ```bash curl -X POST http://localhost:5001/connect/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=password" \ -d "username=user@example.com" \ -d "password=Password123!" \ -d "scope=openid profile email offline_access" ``` | Tham số | Bắt buộc | Mô tả | |---------|----------|-------| | `grant_type` | Có | Phải là `password` | | `username` | Có | Email của user | | `password` | Có | Mật khẩu của user | | `scope` | Không | Các scopes cách nhau bằng dấu cách | ### Refresh Token Làm mới access token mà không cần nhập lại thông tin đăng nhập. ```bash curl -X POST http://localhost:5001/connect/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=refresh_token" \ -d "refresh_token=eyJhbGciOiJSUzI1NiIs..." ``` | Tham số | Bắt buộc | Mô tả | |---------|----------|-------| | `grant_type` | Có | Phải là `refresh_token` | | `refresh_token` | Có | Refresh token hợp lệ | ### Client Credentials (Service-to-Service) Cho các backend services xác thực mà không cần user context. ```bash curl -X POST http://localhost:5001/connect/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=client_credentials" \ -d "client_id=goodgo-service" \ -d "client_secret=service-secret" \ -d "scope=api" ``` | Tham số | Bắt buộc | Mô tả | |---------|----------|-------| | `grant_type` | Có | Phải là `client_credentials` | | `client_id` | Có | Client ID đã đăng ký | | `client_secret` | Có | Client secret | | `scope` | Không | Các scopes yêu cầu | > **Lưu ý:** Client applications phải được đăng ký trong database trước khi sử dụng. ## Thời Hạn Token | Loại Token | Thời hạn | Sử dụng | |------------|----------|---------| | Access Token | 15 phút | API authorization | | Refresh Token | 7 ngày | Làm mới token | ## Các Scopes Hỗ Trợ | Scope | Mô tả | |-------|-------| | `openid` | Bắt buộc cho OIDC | | `profile` | Thông tin profile (tên) | | `email` | Email của user | | `roles` | Các roles của user | | `offline_access` | Nhận refresh token | | `api` | Truy cập API | ## API Endpoints ### Xác Thực | Method | Endpoint | Mô tả | |--------|----------|-------| | `POST` | `/api/v1/auth/register` | Đăng ký user mới | | `POST` | `/connect/token` | OAuth2 token endpoint | | `POST` | `/api/v1/auth/change-password` | Đổi mật khẩu (cần auth) | | `POST` | `/api/v1/auth/logout` | Thu hồi tokens (cần auth) | ### Xác Minh Email | Method | Endpoint | Mô tả | |--------|----------|-------| | `POST` | `/api/v1/auth/send-verification-email` | Gửi link xác minh email (cần auth) | | `POST` | `/api/v1/auth/confirm-email` | Xác nhận email với token | ### Xác Thực Hai Yếu Tố (2FA) | Method | Endpoint | Mô tả | |--------|----------|-------| | `POST` | `/api/v1/auth/2fa/enable` | Bật 2FA (lấy QR code) (cần auth) | | `POST` | `/api/v1/auth/2fa/verify` | Xác minh mã TOTP & kích hoạt (cần auth) | | `POST` | `/api/v1/auth/2fa/disable` | Tắt 2FA (cần auth) | ### Đăng Nhập Mạng Xã Hội | Method | Endpoint | Mô tả | |--------|----------|-------| | `GET` | `/api/v1/auth/external-login/{provider}` | Khởi tạo OAuth flow (Google/Facebook) | | `GET` | `/api/v1/auth/external-callback` | Xử lý OAuth callback | | `GET` | `/api/v1/auth/linked-accounts` | Lấy danh sách OAuth providers đã liên kết (cần auth) | ### Quản Lý User | Method | Endpoint | Mô tả | |--------|----------|-------| | `GET` | `/api/v1/users` | Danh sách users (phân trang) | | `GET` | `/api/v1/users/me` | Thông tin user hiện tại | | `GET` | `/api/v1/users/{id}` | Lấy user theo ID | | `PUT` | `/api/v1/users/{id}` | Cập nhật user | | `DELETE` | `/api/v1/users/{id}` | Xóa user (soft) | ## Ví Dụ Tích Hợp ### JavaScript/TypeScript ```typescript // Đăng nhập const response = await fetch('http://localhost:5001/connect/token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ grant_type: 'password', username: 'user@example.com', password: 'Password123!', scope: 'openid profile email offline_access' }) }); const { access_token, refresh_token } = await response.json(); // Sử dụng token const user = await fetch('http://localhost:5001/api/v1/users/me', { headers: { 'Authorization': `Bearer ${access_token}` } }).then(r => r.json()); ``` ### C# / .NET ```csharp // Đăng nhập var client = new HttpClient(); var content = new FormUrlEncodedContent(new Dictionary { ["grant_type"] = "password", ["username"] = "user@example.com", ["password"] = "Password123!", ["scope"] = "openid profile email offline_access" }); var response = await client.PostAsync("http://localhost:5001/connect/token", content); var tokens = await response.Content.ReadFromJsonAsync(); // Sử dụng token client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokens.AccessToken); var user = await client.GetFromJsonAsync("/api/v1/users/me"); ``` ## Xác Minh Email ### Gửi Email Xác Minh ```bash curl -X POST http://localhost:5001/api/v1/auth/send-verification-email \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{"email": "user@example.com"}' ``` ### Xác Nhận Email ```bash curl -X POST http://localhost:5001/api/v1/auth/confirm-email \ -H "Content-Type: application/json" \ -d '{"userId": "user-guid", "token": "confirmation-token"}' ``` ## Xác Thực Hai Yếu Tố (2FA) ### Bật 2FA ```bash curl -X POST http://localhost:5001/api/v1/auth/2fa/enable \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" ``` **Response:** ```json { "success": true, "data": { "secretKey": "JBSWY3DPEHPK3PXP", "qrCodeBase64": "data:image/png;base64,...", "recoveryCodes": ["code1", "code2", "code3"] } } ``` ### Xác Minh Mã 2FA ```bash curl -X POST http://localhost:5001/api/v1/auth/2fa/verify \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{"code": "123456"}' ``` ### Tắt 2FA ```bash curl -X POST http://localhost:5001/api/v1/auth/2fa/disable \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{"code": "123456"}' ``` ## Đăng Nhập Mạng Xã Hội ### Khởi Tạo OAuth Flow Chuyển hướng user đến: ``` GET http://localhost:5001/api/v1/auth/external-login/Google?returnUrl=http://your-app/callback GET http://localhost:5001/api/v1/auth/external-login/Facebook?returnUrl=http://your-app/callback ``` ### Lấy Danh Sách Tài Khoản Liên Kết ```bash curl http://localhost:5001/api/v1/auth/linked-accounts \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" ``` **Response:** ```json { "success": true, "data": { "linkedProviders": [ {"provider": "Google", "providerDisplayName": "Google"}, {"provider": "Facebook", "providerDisplayName": "Facebook"} ] } } ``` ## Xử Lý Lỗi ### Các Lỗi Thường Gặp | Lỗi | HTTP Code | Mô tả | |-----|-----------|-------| | `invalid_grant` | 400 | Thông tin đăng nhập không hợp lệ | | `invalid_client` | 400 | client_id không xác định | | `invalid_scope` | 400 | Scope yêu cầu không hợp lệ | | `unauthorized` | 401 | Token không hợp lệ/hết hạn | ### Định Dạng Lỗi ```json { "error": "invalid_grant", "error_description": "The username or password is incorrect." } ``` ## Best Practices Bảo Mật 1. **Lưu trữ tokens an toàn** - Sử dụng httpOnly cookies hoặc secure storage 2. **Làm mới tokens chủ động** - Trước khi access token hết hạn 3. **Sử dụng HTTPS trong production** - Không bao giờ gửi credentials qua HTTP 4. **Đăng xuất đúng cách** - Gọi logout endpoint để thu hồi tokens 5. **Validate tokens phía server** - Không tin tưởng validation phía client ## Swagger UI Truy cập tài liệu API tương tác: - **Local**: http://localhost:5001/swagger ## Tài Liệu Liên Quan - [Hướng Dẫn IAM Migration](./iam-migration.md) - [Local Development](./local-development.md) - [Security Architecture](../architecture/security-architecture.md)