Bỏ qua, đến nội dung

Chi tiết luồng xác thực Apple

Mô tả luồng form_post response mode đặc thù của Apple, cookie state, gateway middleware và xử lý user info chỉ gửi lần đầu.

Tổng quan luồng

Sign in with Apple sử dụng form_post response mode — khác với OIDC thông thường (query string), Apple POST dữ liệu qua HTML form. Plugin dùng cookie digiforce_apple cho CSRF state và gateway middleware để xử lý form POST.

Sequence diagram chi tiết

Đặc thù form_post response mode

Apple sử dụng response_mode=form_post thay vì query — đây là đặc thù quan trọng:

Tiêu chíform_post (Apple)query (OIDC thông thường)
Cách trả vềPOST form dataQuery string trong URL
HTTP methodPOSTGET
Bảo mậtAn toàn hơn (data không nằm trong URL)Code hiển thị trong URL/log
Gateway xử lýCần middleware đặc biệtĐọc query string bình thường

Gateway middleware

Vì Apple POST form data (không phải GET redirect), gateway middleware cần xử lý đặc biệt:

  1. Nhận POST request từ Apple
  2. Parse form body → extract state
  3. Giải mã state → xác định ứng dụng đích (app name)
  4. Forward toàn bộ request (bao gồm form body) đến ứng dụng tương ứng

Middleware này cần thiết vì trong kiến trúc multi-app, gateway phải biết route request đến đâu trước khi ứng dụng xử lý.

State CSRF được lưu trong cookie digiforce_apple:

Thuộc tínhGiá trị
Namedigiforce_apple
ValueCSRF token (random string)
HttpOnlytrue
Path/

Khi callback, server so sánh state trong form body với giá trị trong cookie.

User info chỉ lần đầu

Apple chỉ gửi user JSON (chứa tên) khi user authorize lần đầu tiên. Điều này có ý nghĩa:

  • Lần đầu: form POST chứa code, state, và user (JSON với name + email)
  • Các lần sau: form POST chỉ chứa codestate — không có user

Plugin phải lưu tên user vào local account ngay lần đầu. Nếu lần đầu bị lỗi, tên user sẽ mất vĩnh viễn (trừ khi user revoke và re-authorize).

Token exchange và id_token

Sau khi nhận code, plugin exchange lấy tokens:

POST https://appleid.apple.com/auth/token
grant_type=authorization_code
code={code}
client_id={clientId}
client_secret={clientSecret}
redirect_uri={redirectUri}

id_token chứa claims:

  • sub: Apple user ID (ổn định, không đổi giữa các lần đăng nhập)
  • email: email user (real hoặc xxx@privaterelay.appleid.com)
  • email_verified: luôn true với Apple
  • is_private_email: true nếu user chọn "Hide My Email"

Xử lý lỗi

LỗiNguyên nhânGiải pháp
user_cancelled_authorizeUser hủy trong Apple popupKhông cần xử lý — hiển thị lại trang login
State mismatchCookie bị xóa hoặc expiredKiểm tra cookie settings, domain
Invalid clientClient ID/Secret saiKiểm tra Apple Developer config
Redirect URI mismatchAPP_BASE_URL không khớp Return URLĐồng bộ APP_BASE_URL với Apple settings