會員管理平台

第三方登入(Google / LINE / Facebook)與會員中心整合平台

🚀 快速開始

在 Manager 建立服務

登入 MCC Manager,建立群組和服務,取得整合所需的參數。

取得參數:service_suuidGROUP_JWTSERVICE_CODE
設定白名單:將你的 redirect_uri 加入白名單(需完全匹配)

設定 IdP(第三方登入)

在 MCC Manager 中啟用並設定 Google / LINE / Facebook 登入。

IdP Callback URL:https://members.managers.center/auth/idp/{provider}/callback
支援的 Provider:googlelinefacebook

前端整合登入流程

前端導向 MCC 啟動登入,處理回調取得 code,再由後端兌換憑證。

啟動登入:GET /auth/idp/{provider}/start
建議模式:response_mode=code(安全性最高)

📋 快速參考

🔑整合參數

參數 說明 使用位置
service_suuid 服務識別碼 前端
redirect_uri 登入完成後的回調網址 前端
GROUP_JWT 群組 Bearer Token 後端
SERVICE_CODE 服務代碼(X-Service-Code) 後端

⚠️ GROUP_JWTSERVICE_CODE 是敏感資訊,務必存放在後端環境變數中!

🔗關鍵 API 端點

GET
/auth/idp/{provider}/start
啟動第三方登入(前端呼叫)
POST
/auth/idp/exchange
兌換一次性 code(後端呼叫)
POST
/member/check
驗證會員登入狀態
GET
/member/profile
取得會員個人資料

📤回傳模式(response_mode)

fragment
Token 放在 URL fragment
測試用
json
直接回傳 JSON
除錯用

💻 代碼範例

🌐前端:啟動登入

JavaScript
const MCC_BASE = 'https://members.managers.center';
const SERVICE_SUUID = 'your-service-suuid';
const REDIRECT_URI = 'https://your-site.com/callback';

function loginWith(provider) {
  const params = new URLSearchParams({
    service_suuid: SERVICE_SUUID,
    redirect_uri: REDIRECT_URI,
    response_mode: 'code'
  });
  window.location.href = 
    `${MCC_BASE}/auth/idp/${provider}/start?${params}`;
}

📥前端:處理回調

JavaScript
// callback.html - 先檢查錯誤,再處理 code
const params = new URLSearchParams(location.search);
const error = params.get('error');
const errorDescription = params.get('error_description');
const provider = params.get('provider');

if (error === 'idp_not_configured') {
  showMessage(`${provider || '該'} 登入尚未設定,請使用其他方式`);
  return;
}
if (error) {
  showMessage(errorDescription || '登入發生錯誤');
  return;
}

const code = params.get('code');
if (code) {
  // 將 code 送給後端兌換
  fetch('/api/auth/exchange', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ code })
  }).then(r => r.json())
    .then(data => {
      if (data.success) {
        localStorage.setItem('member_suuid', data.data.member_suuid);
        localStorage.setItem('access_token', data.data.accessToken);
      }
    });
}

⚙️後端:兌換 code(Node.js)

JavaScript
const MCC_BASE = 'https://members.managers.center';
const GROUP_JWT = process.env.GROUP_JWT;     // 從環境變數取得
const SERVICE_CODE = process.env.SERVICE_CODE;

app.post('/api/auth/exchange', async (req, res) => {
  const { code } = req.body;
  
  const response = await fetch(`${MCC_BASE}/auth/idp/exchange`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${GROUP_JWT}`,
      'X-Service-Code': SERVICE_CODE,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ code })
  });
  
  const data = await response.json();
  res.json(data);  // { success: true, data: { member_suuid, accessToken } }
});

🔍後端:驗證會員登入狀態(Node.js)

JavaScript
// 驗證會員 accessToken 是否有效
app.post('/api/member/check', async (req, res) => {
  const { member_suuid, access_token } = req.body;
  
  const response = await fetch(`${MCC_BASE}/member/check`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${GROUP_JWT}`,
      'X-Service-Code': SERVICE_CODE,
      'X-Member-Suuid': member_suuid,
      'X-Member-Access-Token': access_token,
      'Content-Type': 'application/json'
    }
  });
  
  const data = await response.json();
  // { success: true, data: { member_suuid, email, display_name, ttl, ... } }
  res.json(data);
});

🔴 錯誤訊息參考

整合時請根據以下錯誤情境進行處理。完整 API 錯誤規格請參考 Swagger 文檔

🔗IdP /start 錯誤(啟動登入)

情境 HTTP 回應形式 error / 參數 說明
缺 service_suuid400JSON/HTMLBAD_REQUESTmissing service_suuid
缺 redirect_uri400JSON/HTMLBAD_REQUESTmissing redirect_uri
找不到 service404JSON/HTMLNOT_FOUNDservice not found
redirect_uri 未白名單400JSON/HTMLBAD_REQUESTredirect_uri not allowed
IdP 未設定302導回 redirect_urierror=idp_not_configured, error_description, provider用戶會被導回前端 callback,需解析 query

⚠️ IdP 未設定時會 302 導回 redirect_uri 並帶 errorerror_descriptionprovider,前端 callback 必須先檢查這些參數。

📥IdP Callback 錯誤

情境HTTPerror說明
缺 code 或 state400BAD_REQUESTmissing code/state
state 無效400BAD_REQUESTinvalid state
IdP 未回傳 email400BAD_REQUESTIdP did not provide email
內部錯誤500INTERNAL_ERRORcallback error

🔄IdP /exchange 錯誤(兌換 code)

情境HTTPerrordetails.reason
無效 code400BAD_REQUESTfield: code
code 已用或過期410GONEcode_consumed_or_expired
群組不符403FORBIDDENgroup_mismatch
服務不符403FORBIDDENservice_mismatch
內部錯誤500INTERNAL_ERRORinternal

👤Member API 常見錯誤

情境HTTPerrordetails.reason
會員不存在404NOT_FOUNDmember_not_found
密碼錯誤401UNAUTHORIZEDinvalid_password
帳號停用403FORBIDDENaccount_disabled
欄位驗證失敗400BAD_REQUESTfield: ...

📦回應格式說明

  • 成功:{ success: true, data: {...}, messages: [...] }
  • 失敗:{ success: false, error: "ERROR_CODE", messages: [...], details?: { reason, field, ... } }
  • 302 導向(IdP 未設定):redirect_uri?error=idp_not_configured&error_description=...&provider=line

📖 資源連結

🔒 安全注意事項

  • ⚠️ Redirect URI 白名單:所有 redirect_uri 必須在 MCC Manager 中註冊,且需完全匹配(包含協定、域名、路徑)
  • ⚠️ 敏感資訊保護:GROUP_JWTSERVICE_CODE 只能存放在後端環境變數,切勿暴露給前端
  • ⚠️ 使用 Code 模式:正式環境建議使用 response_mode=code,避免 token 暴露在 URL 中
  • ⚠️ HTTPS 必須:正式環境務必使用 HTTPS,確保傳輸安全
  • ⚠️ 不記錄敏感資訊:不要在日誌中記錄 accessToken、code 等敏感資訊