#!/usr/bin/env bash # register-oauth-client.sh # # ⚠️ 目前狀態:MC 的 password grant 在 Identity user 上拿不到 sub claim 而 500(已知 MC bug) # 所以這支 script 暫時跑不通。註冊 OAuth client 請走 MC Web UI(見 docs/DEV-SETUP.md)。 # # 保留此檔案是為了: # 1. 等 MC 修好 password flow 後可立刻啟用 # 2. 留下「應該長什麼樣」的程式碼參考 # # 用法(MC 修好後): # bash docker/register-oauth-client.sh # # 需要環境變數(會從 .env.dev / .env 讀,否則用預設): # MC_BASE_URL 預設 http://localhost:5050 # MC_ADMIN_EMAIL 預設 admin@visiona.local # MC_ADMIN_PASSWORD 預設 Admin12345! # VISIONA_REDIRECT_URI 預設 http://localhost:3721/api/auth/callback # OUTPUT_FILE 預設 .env.dev.generated(在 repo 根) set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" if [[ -f "${REPO_ROOT}/.env.dev" ]]; then # shellcheck disable=SC1091 set -a; source "${REPO_ROOT}/.env.dev"; set +a fi MC_BASE_URL="${MC_BASE_URL:-http://localhost:5050}" MC_ADMIN_EMAIL="${MC_ADMIN_EMAIL:-admin@visiona.local}" MC_ADMIN_PASSWORD="${MC_ADMIN_PASSWORD:-Admin12345!}" VISIONA_REDIRECT_URI="${VISIONA_OIDC_REDIRECT_URL:-http://localhost:3721/api/auth/callback}" OUTPUT_FILE="${OUTPUT_FILE:-${REPO_ROOT}/.env.dev.generated}" CYAN='\033[0;36m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; NC='\033[0m' log() { echo -e "${CYAN}[register]${NC} $*"; } ok() { echo -e "${GREEN}[ok]${NC} $*"; } warn() { echo -e "${YELLOW}[warn]${NC} $*"; } err() { echo -e "${RED}[error]${NC} $*" >&2; } require() { command -v "$1" >/dev/null 2>&1 || { err "missing tool: $1(brew install $1)"; exit 1; }; } require curl require jq # ── 1. 拿 admin token(MC password flow,目前有 bug)──────── log "fetching admin token from ${MC_BASE_URL}/oauth/token..." TOKEN_RES=$(curl -sS -X POST "${MC_BASE_URL}/oauth/token" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=password&username=${MC_ADMIN_EMAIL}&password=${MC_ADMIN_PASSWORD}&scope=openid email profile") || { err "MC unreachable at ${MC_BASE_URL}. Is docker compose up?"; exit 1; } if ! echo "${TOKEN_RES}" | head -c 1 | grep -q '{'; then err "MC password grant failed (回應非 JSON,可能 500 error)。" err "已知 MC bug:Identity user principal 缺 sub claim → OpenIddict reject。" err "請改走 MC Web admin UI 註冊 OAuth client,詳見 docs/DEV-SETUP.md。" exit 1 fi ACCESS_TOKEN=$(echo "${TOKEN_RES}" | jq -r '.access_token // empty') if [[ -z "${ACCESS_TOKEN}" || "${ACCESS_TOKEN}" == "null" ]]; then err "failed to get admin token. response:"; echo "${TOKEN_RES}" | jq . >&2 || echo "${TOKEN_RES}" >&2 exit 1 fi ok "got admin token (length=${#ACCESS_TOKEN})" # ── 2. 建 tenant ─────────────────────────────────────────── log "ensuring visionA tenant..." EXISTING_TENANT_ID=$(curl -sS -H "Authorization: Bearer ${ACCESS_TOKEN}" \ "${MC_BASE_URL}/admin/tenants" | jq -r '.[] | select(.name == "visionA") | .id // empty' | head -1) if [[ -n "${EXISTING_TENANT_ID}" ]]; then TENANT_ID="${EXISTING_TENANT_ID}" ok "tenant 'visionA' already exists: ${TENANT_ID}" else TENANT_RES=$(curl -sS -X POST "${MC_BASE_URL}/admin/tenants" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ -d '{"name":"visionA","domains":["visiona.cloud","localhost"],"status":"active"}') TENANT_ID=$(echo "${TENANT_RES}" | jq -r '.id // empty') [[ -z "${TENANT_ID}" ]] && { err "tenant create failed:"; echo "${TENANT_RES}" >&2; exit 1; } ok "created tenant 'visionA': ${TENANT_ID}" fi # ── 3. 建 OAuth client ───────────────────────────────────── log "ensuring OAuth client..." EXISTING_CLIENT_ID=$(curl -sS -H "Authorization: Bearer ${ACCESS_TOKEN}" \ "${MC_BASE_URL}/admin/oauth-clients" | jq -r '.[] | select(.name == "visionA Cloud") | .client_id // empty' | head -1) if [[ -n "${EXISTING_CLIENT_ID}" ]]; then CLIENT_ID="${EXISTING_CLIENT_ID}" ok "OAuth client 'visionA Cloud' already exists: ${CLIENT_ID}" else CLIENT_RES=$(curl -sS -X POST "${MC_BASE_URL}/admin/oauth-clients" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ -d "{\"tenant_id\":\"${TENANT_ID}\",\"name\":\"visionA Cloud\",\"client_type\":\"public\",\"usage\":\"webhook_outbound\",\"redirect_uris\":[\"${VISIONA_REDIRECT_URI}\"]}") CLIENT_ID=$(echo "${CLIENT_RES}" | jq -r '.clientId // .ClientId // empty') [[ -z "${CLIENT_ID}" ]] && { err "OAuth client create failed:"; echo "${CLIENT_RES}" >&2; exit 1; } ok "created OAuth client: ${CLIENT_ID}" fi # ── 4. 寫出 env ──────────────────────────────────────────── cat > "${OUTPUT_FILE}" <