Đặc tả Kỹ thuật API

API Xác thực (Better Auth)
AUTH
Phiên bản1.1.0
URL Cơ sởhttp://localhost:3001/api/auth
Hệ thốngHệ thống Xác thực
ModuleAUTH - Xác thực (Better Auth)
Ngày2026-08-05
Tác giảNam Nguyen
SRS Liên quanSRS Xác thực

Mục lục

1. Tổng quan

1.1 Yêu cầu được giải quyết

Yêu cầu SRSĐầu nối API
FR-001 Đăng ký Người dùngPOST /sign-up/email → RabbitMQ (verification.email) → Email Queue Worker → EMAIL module
FR-002 Đăng nhậpPOST /sign-in/email, POST /sign-in/social, POST /sign-in/username
FR-003 Đăng xuấtPOST /sign-out
FR-004 Làm mới TokenPOST /refresh-token
FR-005 Đặt lại Mật khẩu (Email)POST /request-password-reset → RabbitMQ (password.reset.email) → Email Queue Worker → EMAIL module
FR-006 Đặt lại Mật khẩu (Số điện thoại)POST /request-password-reset → RabbitMQ (password.reset.sms) → SMS Queue Worker → SMS module
FR-007 Đổi Mật khẩuPOST /change-password
FR-008 Xác minh EmailGET /verify-email, POST /send-verification-email
FR-009 Xác minh Số điện thoạiPOST /send-verification-sms (qua module SMS)
FR-010 Quản lý Người dùngGET /admin/list-users, GET /admin/get-user, POST /admin/create-user, POST /admin/update-user, POST /admin/remove-user
FR-011 Quản lý Vai tròPOST /admin/set-role, POST /organization/create-role, POST /organization/update-role, POST /organization/delete-role
FR-012 Xác thực Xã hộiPOST /sign-in/social, POST /link-social, POST /unlink-account
FR-013 Quản lý Phiên làm việcGET /list-sessions, POST /revoke-session, POST /revoke-sessions, POST /revoke-other-sessions
FR-014 Khóa Tài khoản/Đăng nhập giả danhPOST /admin/ban-user, POST /admin/unban-user, POST /admin/impersonate-user
FR-015 Quản lý Tổ chứcPOST /organization/create, POST /organization/update, POST /organization/delete, GET /organization/list
FR-016 Quản lý NhómPOST /organization/create-team, POST /organization/update-team, POST /organization/remove-team
FR-017 Quản lý Lời mờiPOST /organization/invite-member, POST /organization/accept-invitation, POST /organization/reject-invitation
FR-018 Gửi lại Lời mờiPOST /organization/resend-invitation
FR-019 Thu hồi Lời mờiDELETE /organization/cancel-invitation
FR-020 Xác minh Token Lời mờiGET /organization/verify-invitation

1.2 Xác thực

Tất cả đầu nối yêu cầu một trong các phương thức sau:

Các đầu nối công khai (đăng ký, đăng nhập, yêu cầu đặt lại mật khẩu) không yêu cầu xác thực.

1.3 Tóm tắt Đầu nối

NhãnSố lượngMô tả
Default31Xác thực cốt lõi: đăng ký, đăng nhập, phiên làm việc, mật khẩu, email, hồ sơ người dùng
Admin15Quản lý người dùng, khóa/mở khóa, đăng nhập giả danh, thu hồi phiên
Organization27CRUD tổ chức, thành viên, nhóm, lời mời, vai trò, quyền hạn
Jwt2JSON Web Key Set và các đầu nối JWT token

2. Định dạng Phản hồi

2.1 Phản hồi Thành công

{
  "token": "eyJhbGciOiJSUzI1NiIs...",
  "user": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "John Doe",
    "email": "[email protected]",
    "emailVerified": true,
    "role": "user",
    "createdAt": "2026-07-24T10:30:00Z",
    "updatedAt": "2026-07-24T10:30:00Z"
  }
}

2.2 Phản hồi Lỗi

{
  "message": "Invalid credentials"
}

3. Schema

3.1 Người dùng

TrườngLoạiBắt buộcMô tả
idstringĐịnh danh duy nhất (UUID)
namestringTên hiển thị của người dùng
emailstringĐịa chỉ email của người dùng
emailVerifiedbooleanLiệu email đã được xác minh chưa (mặc định: false)
imagestringKhôngURL ảnh hồ sơ
createdAtdatetimeThời điểm tạo tài khoản
updatedAtdatetimeThời điểm cập nhật cuối cùng
rolestringVai trò hệ thống: "user" hoặc "super_admin" (mặc định: "user")
bannedbooleanKhôngLiệu người dùng có bị khóa không (mặc định: false)
banReasonstringKhôngLý do khóa tài khoản
banExpiresdatetimeKhôngThời điểm hết hạn khóa

Mô tả Vai trò Hệ thống:

Vai tròMô tảTự đăng ký
userTài khoản người dùng tiêu chuẩn (mặc định). Người dùng có thể tạo tổ chức và nhận vai trò cấp tổ chức (HR, Candidate, Employer).Có (mặc định)
super_adminQuản trị viên hệ thống có quyền truy cập đầy đủ. Có thể quản lý tất cả người dùng, vai trò và tổ chức.Không (chỉ tạo bởi admin qua POST /admin/create-user)

Lưu ý: Các vai trò cấp tổ chức (HR, Candidate, Employer) được xác định theo từng tổ chức và được gán cho thành viên thông qua hệ thống vai trò tổ chức (xem phần 6.3). Chúng không phải là vai trò cấp hệ thống.

3.2 Phiên làm việc

TrườngLoạiBắt buộcMô tả
idstringĐịnh danh phiên
expiresAtdatetimeThời điểm hết hạn phiên
tokenstringToken phiên
createdAtdatetimeThời điểm tạo phiên
updatedAtdatetimeThời điểm cập nhật cuối cùng
ipAddressstringKhôngĐịa chỉ IP của client
userAgentstringKhôngUser agent của client
userIdstringID người dùng liên kết
impersonatedBystringKhôngID Admin nếu đang đăng nhập giả danh
activeOrganizationIdstringKhôngID tổ chức đang hoạt động
activeTeamIdstringKhôngID nhóm đang hoạt động

3.3 Tài khoản

TrườngLoạiBắt buộcMô tả
idstringĐịnh danh tài khoản
accountIdstringID tài khoản của nhà cung cấp
providerIdstringĐịnh danh nhà cung cấp (ví dụ: "google", "github")
userIdstringID người dùng liên kết
accessTokenstringKhôngToken truy cập OAuth
refreshTokenstringKhôngToken làm mới OAuth
idTokenstringKhôngOIDC ID token
accessTokenExpiresAtdatetimeKhôngThời hạn token truy cập
refreshTokenExpiresAtdatetimeKhôngThời hạn token làm mới
scopestringKhôngPhạm vi OAuth
passwordstringKhôngBăm mật khẩu (chỉ cho nhà cung cấp email)
createdAtdatetimeThời điểm tạo tài khoản
updatedAtdatetimeThời điểm cập nhật cuối cùng

3.4 Xác minh

TrườngLoạiBắt buộcMô tả
idstringĐịnh danh xác minh
identifierstringĐối tượng xác minh (email, số điện thoại)
valuestringGiá trị xác minh (OTP, token)
expiresAtdatetimeThời hạn xác minh
createdAtdatetimeThời điểm tạo
updatedAtdatetimeThời điểm cập nhật cuối cùng

3.5 Tổ chức

TrườngLoạiBắt buộcMô tả
idstringĐịnh danh tổ chức
namestringTên tổ chức
slugstringSlug thân thiện với URL
logostringKhôngURL logo
createdAtdatetimeThời điểm tạo
metadatastringKhôngChuỗi metadata JSON

3.6 Nhóm

TrườngLoạiBắt buộcMô tả
idstringĐịnh danh nhóm
namestringTên nhóm
organizationIdstringID tổ chức cha
createdAtdatetimeThời điểm tạo
updatedAtdatetimeThời điểm cập nhật cuối cùng

3.7 Lời mời

TrườngLoạiBắt buộcMô tả
idstringĐịnh danh lời mời
organizationIdstringID tổ chức đích
emailstringEmail người được mời
tokenHashstringKhôngBăm SHA-256 của token lời mời (không bao giờ hiển thị trong phản hồi)
rolestringKhôngVai trò được gán
teamIdstringKhôngID nhóm đích
employerIdstringKhôngID Employer (bắt buộc cho vai trò HR)
statusstringTrạng thái: pending, accepted, rejected, canceled, expired, revoked
expiresAtdatetimeThời hạn lời mời
acceptedAtdatetimeKhôngThời điểm lời mời được chấp nhận
inviterIdstringNgười dùng đã gửi lời mời
createdAtdatetimeThời điểm tạo
updatedAtdatetimeThời điểm cập nhật cuối cùng

4. Đầu nối Xác thực Cốt lõi

4.1 Đăng ký

POST /sign-up/email (Công khai) FR-001

Đăng ký người dùng mới bằng email và mật khẩu. Người dùng được gán vai trò hệ thống user theo mặc định.

Lưu ý: Tài khoản super_admin không thể tự đăng ký. Chúng phải được tạo bởi admin qua POST /admin/create-user.

Xử lý Bất đồng bộ: Sau khi tạo tài khoản, hệ thống publish sự kiện verification.email.requested lên RabbitMQ (queue: verification.email). Email queue worker bên trong AUTH service consume sự kiện và gọi EMAIL module để gửi email xác minh. Quá trình gửi email diễn ra bất đồng bộ — không chặn response trả về cho client.

Yêu cầu:

{
  "name": "John Doe",
  "email": "[email protected]",
  "password": "securepassword123"
}

Các trường Yêu cầu:

TrườngLoạiBắt buộcMô tả
namestringTên hiển thị của người dùng (2-100 ký tự)
emailstringĐịa chỉ email duy nhất
passwordstringTối thiểu 8 ký tự, ít nhất 1 chữ hoa, 1 chữ thường, 1 chữ số
rolestringKhôngEnum: "user" (mặc định). Chỉ "user" được phép cho tự đăng ký.

Phản hồi 200:

{
  "token": "eyJhbGciOiJSUzI1NiIs...",
  "user": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "John Doe",
    "email": "[email protected]",
    "emailVerified": false,
    "role": "user",
    "createdAt": "2026-08-05T10:30:00Z",
    "updatedAt": "2026-08-05T10:30:00Z"
  }
}

Lưu ý: Response trả về ngay sau khi tạo tài khoản. Email xác minh được gửi bất đồng bộ qua RabbitMQ — có thể mất vài giây đến vài phút. Người dùng có thể yêu cầu gửi lại qua POST /send-verification-email nếu không nhận được.

Lỗi 400 — Vai trò không hợp lệ:

{
  "message": "Role must be 'user'. super_admin accounts are created by admin."
}

4.2 Đăng nhập

POST /sign-in/email (Công khai) FR-002

Đăng nhập bằng email và mật khẩu.

Yêu cầu:

{
  "email": "[email protected]",
  "password": "securepassword123"
}

Phản hồi 200:

{
  "token": "eyJhbGciOiJSUzI1NiIs...",
  "user": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "John Doe",
    "email": "[email protected]",
    "emailVerified": true,
    "role": "user"
  }
}

POST /sign-in/social (Công khai) FR-012

Đăng nhập bằng nhà cung cấp xã hội (Google, GitHub, v.v.).

Yêu cầu:

{
  "provider": "google",
  "callbackURL": "http://localhost:3000/dashboard"
}

Phản hồi 200:

{
  "url": "https://accounts.google.com/o/oauth2/auth?...",
  "redirect": true
}

Các nhà cung cấp được hỗ trợ: apple, atlassian, cognito, discord, facebook, figma, github, microsoft, google, huggingface, slack, spotify, twitch, twitter, dropbox, kick, linear, linkedin, gitlab, tiktok, reddit, roblox, salesforce, vk, zoom, notion, kakao, naver, line, paybin, paypal, polar, railway, vercel, wechat

GET /callback/{id} (Công khai)

Đầu nối callback OAuth. Xử lý chuyển hướng từ các nhà cung cấp xã hội.

POST /callback/{id} (Công khai)

Callback OAuth với trao đổi mã.

Yêu cầu:

{
  "code": "authorization_code",
  "state": "csrf_state"
}

4.3 Quản lý Phiên làm việc

GET /get-session FR-013

Lấy thông tin phiên hiện tại.

Phản hồi 200:

{
  "session": {
    "id": "session-123",
    "expiresAt": "2026-08-12T10:30:00Z",
    "token": "abc...",
    "userId": "550e8400-e29b-41d4-a716-446655440000",
    "ipAddress": "192.168.1.1",
    "userAgent": "Mozilla/5.0..."
  },
  "user": { ... }
}

POST /get-session

Lấy thông tin phiên hiện tại (biến thể POST).

POST /sign-out FR-003

Hủy bỏ phiên hiện tại.

Phản hồi 200: { "success": true }

GET /list-sessions FR-013

Liệt kê tất cả các phiên đang hoạt động của người dùng hiện tại.

Phản hồi 200:

[
  {
    "id": "session-123",
    "expiresAt": "2026-08-12T10:30:00Z",
    "ipAddress": "192.168.1.1",
    "userAgent": "Mozilla/5.0...",
    "createdAt": "2026-08-05T10:30:00Z"
  }
]

POST /revoke-session

Thu hồi một phiên cụ thể.

Yêu cầu:

{
  "sessionId": "session-123"
}

POST /revoke-sessions

Thu hồi tất cả các phiên của người dùng hiện tại.

POST /revoke-other-sessions

Thu hồi tất cả các phiên ngoại trừ phiên hiện tại.

POST /update-session

Cập nhật metadata phiên (ví dụ: tổ chức đang hoạt động).

Yêu cầu:

{
  "activeOrganizationId": "org-123"
}

POST /refresh-token FR-004

Làm mới token truy cập bằng token làm mới.

Phản hồi 200:

{
  "token": "eyJhbGciOiJSUzI1NiIs...",
  "session": { ... }
}

POST /get-access-token

Lấy token truy cập mới cho phiên hiện tại.

4.4 Quản lý Mật khẩu

POST /change-password FR-007

Đổi mật khẩu (yêu cầu mật khẩu hiện tại).

Yêu cầu:

{
  "currentPassword": "oldpassword",
  "newPassword": "newpassword123"
}

POST /request-password-reset (Công khai) FR-005

Yêu cầu đặt lại mật khẩu. Gửi liên kết đặt lại qua email (hoặc OTP qua SMS).

Xử lý Bất đồng bộ: Sau khi tạo reset token, hệ thống publish sự kiện password.reset.email.requested (hoặc password.reset.sms.requested) lên RabbitMQ. Email/SMS queue worker trong AUTH consume và gọi EMAIL/SMS module để gửi. Response trả về ngay — không chờ gửi xong.

Yêu cầu (Email):

{
  "email": "[email protected]",
  "redirectTo": "http://localhost:3000/reset-password"
}

Yêu cầu (SMS):

{
  "phone": "+84901234567"
}

Phản hồi 200:

{
  "message": "If the email exists, a reset link has been sent"
}

Lưu ý: Response luôn trả về 200 với cùng message để không tiết lộ email/SĐT có tồn tại hay không.

GET /reset-password/{token} (Công khai)

Callback đặt lại mật khẩu. Xác thực token đặt lại.

POST /reset-password (Công khai) FR-005

Hoàn tất đặt lại mật khẩu bằng token (email) hoặc OTP (SMS).

Yêu cầu (Email — dùng token):

{
  "token": "reset-token-abc",
  "newPassword": "newpassword123"
}

Yêu cầu (SMS — dùng OTP):

{
  "otp": "123456",
  "newPassword": "newpassword123"
}

Phản hồi 200:

{
  "message": "Password reset successfully"
}

Lỗi 400 — Token/OTP không hợp lệ:

{
  "message": "Invalid or expired reset token"
}

POST /verify-password

Xác thực mật khẩu hiện tại mà không thay đổi nó.

Yêu cầu:

{
  "password": "currentpassword"
}

4.5 Xác minh Email

GET /verify-email (Công khai) FR-008

Xác minh email qua liên kết xác minh. Được gọi khi người dùng nhấp vào liên kết trong email.

Truy vấn: ?token=abc123&callbackURL=http://localhost:3000

POST /send-verification-email FR-008

Gửi email xác minh cho người dùng hiện tại.

Yêu cầu:

{
  "email": "[email protected]",
  "callbackURL": "http://localhost:3000/verified"
}

POST /change-email

Thay đổi email người dùng (gửi xác minh đến email mới).

Yêu cầu:

{
  "newEmail": "[email protected]"
}

4.6 Hồ sơ Người dùng

POST /update-user FR-010

Cập nhật hồ sơ người dùng hiện tại.

Yêu cầu:

{
  "name": "John Updated",
  "image": "https://example.com/avatar.jpg"
}

POST /delete-user

Yêu cầu xóa tài khoản. Gửi email xác nhận.

GET /delete-user/callback (Công khai)

Xác nhận xóa tài khoản qua liên kết email.

GET /account-info

Lấy thông tin tài khoản hiện tại.

4.7 Liên kết Tài khoản

POST /link-social

Liên kết tài khoản xã hội với người dùng hiện tại.

Yêu cầu:

{
  "provider": "github",
  "callbackURL": "http://localhost:3000/settings"
}

POST /unlink-account

Hủy liên kết tài khoản xã hội khỏi người dùng hiện tại.

Yêu cầu:

{
  "providerId": "github",
  "accountId": "account-123"
}

GET /list-accounts

Liệt kê tất cả các tài khoản đã liên kết của người dùng hiện tại.

4.8 Tiện ích

GET /ok

Đầu nối kiểm tra sức khỏe.

Phản hồi 200: { "ok": true }

GET /error

Đầu nối trang lỗi.

5. Đầu nối Admin

Tất cả đầu nối admin đều yêu cầu vai trò admin.

POST /admin/list-users FR-010

Liệt kê tất cả người dùng với phân trang.

Yêu cầu:

{
  "limitValue": 20,
  "offsetValue": 0
}

POST /admin/get-user

Lấy thông tin người dùng theo ID.

Yêu cầu:

{
  "userId": "550e8400-e29b-41d4-a716-446655440000"
}

POST /admin/create-user

Tạo người dùng mới (admin). Đây là cách duy nhất để tạo tài khoản super_admin.

Yêu cầu:

{
  "name": "Jane Doe",
  "email": "[email protected]",
  "password": "tempPassword123",
  "role": "super_admin"
}

Tùy chọn Vai trò: user, super_admin

POST /admin/update-user

Cập nhật thông tin người dùng (admin).

Yêu cầu:

{
  "userId": "550e8400-e29b-41d4-a716-446655440000",
  "name": "Jane Updated",
  "role": "super_admin"
}

POST /admin/remove-user

Xóa vĩnh viễn người dùng.

Yêu cầu:

{
  "userId": "550e8400-e29b-41d4-a716-446655440000"
}

POST /admin/set-role FR-011

Đặt vai trò hệ thống cho người dùng.

Yêu cầu:

{
  "userId": "550e8400-e29b-41d4-a716-446655440000",
  "role": "super_admin"
}

Tùy chọn Vai trò: user, super_admin

POST /admin/ban-user FR-014

Khóa người dùng.

Yêu cầu:

{
  "userId": "550e8400-e29b-41d4-a716-446655440000",
  "banReason": "Violation of terms",
  "banExpiresIn": 86400
}

POST /admin/unban-user

Mở khóa người dùng.

Yêu cầu:

{
  "userId": "550e8400-e29b-41d4-a716-446655440000"
}

POST /admin/impersonate-user

Đăng nhập giả danh người dùng (phiên admin).

Yêu cầu:

{
  "userId": "550e8400-e29b-41d4-a716-446655440000"
}

POST /admin/stop-impersonating

Dừng đăng nhập giả danh và quay lại phiên admin.

POST /admin/list-user-sessions

Liệt kê tất cả các phiên của một người dùng cụ thể.

Yêu cầu:

{
  "userId": "550e8400-e29b-41d4-a716-446655440000"
}

POST /admin/revoke-user-session

Thu hồi một phiên cụ thể của người dùng.

Yêu cầu:

{
  "userId": "550e8400-e29b-41d4-a716-446655440000",
  "sessionId": "session-123"
}

POST /admin/revoke-user-sessions

Thu hồi tất cả các phiên của người dùng.

Yêu cầu:

{
  "userId": "550e8400-e29b-41d4-a716-446655440000"
}

POST /admin/set-user-password

Đặt mật khẩu cho người dùng (admin, không yêu cầu mật khẩu hiện tại).

Yêu cầu:

{
  "userId": "550e8400-e29b-41d4-a716-446655440000",
  "newPassword": "newpassword123"
}

POST /admin/has-permission

Kiểm tra xem admin có một quyền cụ thể hay không.

Yêu cầu:

{
  "permission": "user:delete"
}

6. Đầu nối Tổ chức

POST /organization/create FR-015

Tạo tổ chức mới.

Yêu cầu:

{
  "name": "Acme Corp",
  "slug": "acme-corp",
  "logo": "https://example.com/logo.png"
}

POST /organization/update

Cập nhật thông tin tổ chức.

Yêu cầu:

{
  "organizationId": "org-123",
  "name": "Acme Corporation"
}

POST /organization/delete

Xóa tổ chức.

Yêu cầu:

{
  "organizationId": "org-123"
}

POST /organization/set-active

Đặt tổ chức đang hoạt động cho phiên hiện tại.

Yêu cầu:

{
  "organizationId": "org-123"
}

GET /organization/get-full-organization

Lấy thông tin đầy đủ của tổ chức bao gồm thành viên, nhóm, lời mời.

Truy vấn: ?organizationId=org-123

GET /organization/list

Liệt kê tất cả các tổ chức của người dùng hiện tại.

GET /organization/get-active-member

Lấy thông tin thành viên của người dùng hiện tại trong tổ chức đang hoạt động.

GET /organization/get-active-member-role

Lấy vai trò của người dùng hiện tại trong tổ chức đang hoạt động.

GET /organization/list-members

Liệt kê tất cả thành viên của tổ chức đang hoạt động.

Truy vấn: ?organizationId=org-123&limitValue=20&offsetValue=0

POST /organization/remove-member

Xóa thành viên khỏi tổ chức.

Yêu cầu:

{
  "organizationId": "org-123",
  "userId": "user-456"
}

POST /organization/update-member-role

Cập nhật vai trò của thành viên trong tổ chức.

Yêu cầu:

{
  "organizationId": "org-123",
  "userId": "user-456",
  "role": "HR"
}

POST /organization/leave

Rời khỏi tổ chức hiện tại.

Yêu cầu:

{
  "organizationId": "org-123"
}

POST /organization/check-slug

Kiểm tra xem slug tổ chức có khả dụng không.

Yêu cầu:

{
  "slug": "acme-corp"
}

GET /organization/list-user-invitations

Liệt kê các lời mời đang chờ xử lý cho người dùng hiện tại.

6.1 Lời mời

POST /organization/invite-member FR-017

Mời thành viên vào tổ chức. Tạo token bảo mật (băm SHA-256 được lưu trữ, token gốc gửi qua email).

Yêu cầu:

{
  "organizationId": "org-123",
  "email": "[email protected]",
  "role": "HR",
  "teamId": "team-789",
  "employerId": "emp-456"
}

Các trường Yêu cầu:

TrườngLoạiBắt buộcMô tả
organizationIdstringID tổ chức đích
emailstringĐịa chỉ email người được mời
rolestringVai trò tổ chức: HR, Candidate, Employer
teamIdstringKhôngID nhóm đích
employerIdstringKhôngID Employer (bắt buộc cho vai trò HR)

Phản hồi 200:

{
  "id": "inv-123",
  "email": "[email protected]",
  "role": "HR",
  "status": "pending",
  "expiresAt": "2026-08-12T10:30:00Z"
}

Lỗi 409 — Trùng lặp:

{
  "message": "A pending invitation already exists for this email with the same role"
}

GET /organization/get-invitation

Lấy thông tin lời mời.

Truy vấn: ?id=inv-123

GET /organization/list-invitations

Liệt kê tất cả lời mời của tổ chức.

Truy vấn: ?organizationId=org-123

POST /organization/accept-invitation

Chấp nhận lời mời.

Yêu cầu:

{
  "invitationId": "inv-123"
}

POST /organization/reject-invitation

Từ chối lời mời.

Yêu cầu:

{
  "invitationId": "inv-123"
}

POST /organization/cancel-invitation

Hủy lời mời đang chờ xử lý.

Yêu cầu:

{
  "invitationId": "inv-123"
}

GET /organization/verify-invitation (Công khai) FR-020

Xác minh tính hợp lệ của token lời mời. Không yêu cầu xác thực. Được sử dụng bởi frontend khi người dùng nhấp vào liên kết lời mời từ email.

Truy vấn: ?token={raw_token}

Phản hồi 200 — Hợp lệ:

{
  "valid": true,
  "invitation": {
    "id": "inv-123",
    "email": "[email protected]",
    "role": "HR",
    "organizationId": "org-123",
    "expiresAt": "2026-08-12T10:30:00Z"
  }
}

Phản hồi 200 — Không hợp lệ (hết hạn):

{
  "valid": false,
  "reason": "expired"
}

Phản hồi 200 — Không hợp lệ (đã chấp nhận):

{
  "valid": false,
  "reason": "accepted"
}

Phản hồi 200 — Không hợp lệ (đã thu hồi):

{
  "valid": false,
  "reason": "revoked"
}

Lỗi 404 — Token không tìm thấy:

{
  "message": "Invalid invitation token"
}

POST /organization/resend-invitation FR-018

Gửi lại lời mời với token mới. Token trước đó bị vô hiệu hóa. Yêu cầu xác thực và là chủ sở hữu.

Yêu cầu:

{
  "invitationId": "inv-123"
}

Phản hồi 200:

{
  "id": "inv-123",
  "email": "[email protected]",
  "status": "pending",
  "expiresAt": "2026-08-12T10:30:00Z",
  "message": "Invitation resent successfully"
}

Lỗi 403 — Không phải chủ sở hữu:

{
  "message": "Only the original inviter can resend this invitation"
}

Lỗi 409 — Đã chấp nhận:

{
  "message": "Cannot resend an accepted invitation"
}

DELETE /organization/cancel-invitation FR-019

Thu hồi lời mời đang chờ xử lý. Chỉ người mời ban đầu mới có thể thu hồi. Lời mời đã chấp nhận hoặc đã thu hồi không thể thu hồi lại.

Yêu cầu:

{
  "invitationId": "inv-123"
}

Phản hồi 200:

{
  "message": "Invitation revoked successfully"
}

Lỗi 403 — Không phải chủ sở hữu:

{
  "message": "Only the original inviter can revoke this invitation"
}

Lỗi 409 — Đã chấp nhận/đã thu hồi:

{
  "message": "Cannot revoke an already accepted or revoked invitation"
}

6.2 Nhóm

POST /organization/create-team FR-016

Tạo nhóm trong tổ chức.

Yêu cầu:

{
  "organizationId": "org-123",
  "name": "Engineering"
}

GET /organization/list-teams

Liệt kê tất cả các nhóm trong tổ chức.

Truy vấn: ?organizationId=org-123

GET /organization/list-user-teams

Liệt kê các nhóm mà người dùng hiện tại thuộc về.

POST /organization/update-team

Cập nhật thông tin nhóm.

Yêu cầu:

{
  "teamId": "team-789",
  "name": "Engineering Team"
}

POST /organization/remove-team

Xóa nhóm khỏi tổ chức.

Yêu cầu:

{
  "teamId": "team-789"
}

POST /organization/set-active-team

Đặt nhóm đang hoạt động cho phiên hiện tại.

Yêu cầu:

{
  "teamId": "team-789"
}

GET /organization/list-team-members

Liệt kê thành viên của một nhóm.

Truy vấn: ?teamId=team-789

POST /organization/add-team-member

Thêm thành viên vào nhóm.

Yêu cầu:

{
  "teamId": "team-789",
  "userId": "user-456"
}

POST /organization/remove-team-member

Xóa thành viên khỏi nhóm.

Yêu cầu:

{
  "teamId": "team-789",
  "userId": "user-456"
}

6.3 Vai trò Tổ chức

Mỗi tổ chức có thể định nghĩa các vai trò riêng với quyền chi tiết được giới hạn trong phạm vi tổ chức đó. Các vai trò này độc lập với vai trò cấp hệ thống (user, super_admin).

Các Vai trò Tổ chức Tiêu chuẩn:

Vai tròMô tảQuyền thông thường
EmployerChủ sở hữu/quản trị viên tổ chức quản lý hồ sơ công ty và tin tuyển dụngjob:create, job:update, job:delete, application:read, member:read, settings:read, settings:update
HRThành viên nhóm tuyển dụng nội bộ quản lý quy trình tuyển dụngjob:read, job:create, job:update, application:read, application:update, interview:create, interview:update, member:read
CandidateNgười tìm việc ứng tuyển vào các vị trí trong tổ chứcjob:read, application:create, application:read (chỉ của bản thân)

Lưu ý: Khi người dùng tạo tổ chức, họ tự động nhận vai trò Employer trong tổ chức đó. Các vai trò bổ sung có thể được tạo qua POST /organization/create-role và gán cho thành viên qua lời mời hoặc POST /organization/update-member-role.

Quy tắc Phân quyền

Hành độngĐược phép cho
Tạo vai tròChủ sở hữu hoặc quản trị viên tổ chức
Cập nhật vai tròChủ sở hữu hoặc quản trị viên tổ chức
Xóa vai tròChủ sở hữu hoặc quản trị viên tổ chức
Liệt kê vai tròTất cả thành viên tổ chức
Lấy vai tròTất cả thành viên tổ chức
Kiểm tra quyềnTất cả người dùng đã xác thực

Danh mục Quyền

Các quyền hợp lệ tuân theo định dạng resource:action. Nhiều quyền được ngăn cách bằng dấu phẩy.

QuyềnMô tả
member:readXem thành viên tổ chức
member:updateCập nhật vai trò thành viên
member:deleteXóa thành viên khỏi tổ chức
job:readXem tin tuyển dụng
job:createTạo tin tuyển dụng mới
job:updateCập nhật tin tuyển dụng
job:deleteXóa tin tuyển dụng
application:readXem đơn ứng tuyển
application:updateCập nhật trạng thái đơn ứng tuyển
application:deleteXóa đơn ứng tuyển
interview:readXem phỏng vấn
interview:createLên lịch phỏng vấn
interview:updateCập nhật thông tin phỏng vấn
interview:deleteHủy phỏng vấn
report:readXem báo cáo và phân tích
report:createTạo báo cáo
settings:readXem cài đặt tổ chức
settings:updateCập nhật cài đặt tổ chức

Quy tắc Kiểm tra

POST /organization/create-role

Tạo vai trò tùy chỉnh trong tổ chức.

Yêu cầu:

{
  "organizationId": "org-123",
  "role": "recruiter",
  "description": "Can manage jobs and applications",
  "permission": "job:read,job:create,job:update,application:read,application:update"
}

POST /organization/update-role

Cập nhật vai trò tổ chức.

Yêu cầu:

{
  "organizationId": "org-123",
  "roleId": "role-123",
  "description": "Updated description",
  "permission": "job:read,job:create,job:update,job:delete,application:read,application:update"
}

POST /organization/delete-role

Xóa vai trò tùy chỉnh khỏi tổ chức. Không thể xóa nếu có thành viên đang được gán vai trò này.

Yêu cầu:

{
  "organizationId": "org-123",
  "roleId": "role-123"
}

GET /organization/list-roles

Liệt kê tất cả vai trò trong tổ chức.

Truy vấn: ?organizationId=org-123

Phản hồi 200:

{
  "roles": [
    {
      "id": "role-123",
      "name": "recruiter",
      "description": "Can manage jobs and applications",
      "permissions": ["job:read", "job:create", "job:update", "application:read", "application:update"],
      "memberCount": 5,
      "createdAt": "2026-08-05T10:30:00Z"
    }
  ]
}

GET /organization/get-role

Lấy thông tin vai trò.

Truy vấn: ?organizationId=org-123&roleId=role-123

POST /organization/has-permission

Kiểm tra xem người dùng hiện tại có một quyền trong tổ chức hay không.

Yêu cầu:

{
  "organizationId": "org-123",
  "permission": "job:create"
}

Phản hồi 200:

{
  "hasPermission": true
}

7. Đầu nối JWT

GET /jwks

Lấy JSON Web Key Set để xác thực JWT.

Phản hồi 200:

{
  "keys": [
    {
      "kty": "RSA",
      "kid": "key-123",
      "use": "sig",
      "n": "...",
      "e": "AQAB"
    }
  ]
}

GET /token

Lấy JWT token đã ký cho phiên hiện tại.

8. Mã Lỗi

Trạng thái HTTPMã LỗiMô tả
400VALIDATION_ERRORKiểm tra yêu cầu thất bại (tham số thiếu/không hợp lệ)
401UNAUTHORIZEDThiếu hoặc xác thực không hợp lệ
401INVALID_CREDENTIALSSai email/số điện thoại hoặc mật khẩu
401TOKEN_EXPIREDJWT token đã hết hạn
403FORBIDDENKhông đủ quyền hạn
404NOT_FOUNDKhông tìm thấy tài nguyên
409CONFLICTEmail hoặc số điện thoại đã được đăng ký; lời mời trùng lặp
410INVITATION_EXPIREDToken lời mời đã hết hạn
429RATE_LIMITEDQuá nhiều yêu cầu
500INTERNAL_ERRORLỗi máy chủ