Files
proxmox/scripts/deployment/keycloak-sankofa-ensure-client-redirects.sh
defiQUG 7f3dcf2513 feat(sankofa): public web CT 7806, portal NPM/DNS defaults, Keycloak redirect helper
- Provision/sync scripts and systemd for corporate Next on 7806; IP_SANKOFA_PUBLIC_WEB for apex NPM
- Portal stack: NEXTAUTH_URL default portal.sankofa.nexus; NPM fleet + migrate + DNS ordering
- keycloak-sankofa-ensure-client-redirects.sh (KEYCLOAK_ADMIN_PASSWORD); .env.master.example hints
- Docs: task list, inventory, FQDN/E2E/EXPECTED_WEB_CONTENT, AGENTS pointers

Made-with: Cursor
2026-03-29 13:41:02 -07:00

102 lines
3.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# Ensure Keycloak OIDC client has redirect URIs and web origins for portal/admin hostnames.
# Uses Admin REST API (password grant on master realm). Set secrets in .env (not committed).
#
# Required env: KEYCLOAK_ADMIN_PASSWORD
# Optional: KEYCLOAK_URL (default https://keycloak.sankofa.nexus), KEYCLOAK_ADMIN (default admin),
# KEYCLOAK_REALM (default master), KEYCLOAK_CLIENT_ID (default sankofa-portal)
#
# Usage: from repo root with .env loaded:
# ./scripts/deployment/keycloak-sankofa-ensure-client-redirects.sh
# ./scripts/deployment/keycloak-sankofa-ensure-client-redirects.sh --dry-run
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
if [ -f "$PROJECT_ROOT/.env" ]; then
set +u
set -a
# shellcheck source=/dev/null
source "$PROJECT_ROOT/.env" 2>/dev/null || true
set +a
set -u
fi
KEYCLOAK_URL="${KEYCLOAK_URL:-https://keycloak.sankofa.nexus}"
REALM="${KEYCLOAK_REALM:-master}"
CLIENT_ID="${KEYCLOAK_CLIENT_ID:-sankofa-portal}"
ADMIN_USER="${KEYCLOAK_ADMIN:-admin}"
ADMIN_PASS="${KEYCLOAK_ADMIN_PASSWORD:-}"
DRY=0
[[ "${1:-}" == "--dry-run" ]] && DRY=1
if [ -z "$ADMIN_PASS" ]; then
echo "KEYCLOAK_ADMIN_PASSWORD is not set. Add it to .env (or export) and re-run." >&2
echo "Without it, update the client manually: Valid redirect URIs + Web origins for portal/admin." >&2
exit 1
fi
TOKEN_JSON=$(curl -sS -X POST "${KEYCLOAK_URL}/realms/master/protocol/openid-connect/token" \
-d "grant_type=password" \
-d "client_id=admin-cli" \
-d "username=${ADMIN_USER}" \
-d "password=${ADMIN_PASS}")
TOKEN=$(echo "$TOKEN_JSON" | jq -r '.access_token // empty')
if [ -z "$TOKEN" ] || [ "$TOKEN" = "null" ]; then
echo "Failed to obtain admin token (check URL, user, password)." >&2
echo "$TOKEN_JSON" | jq -r '.error_description // .error // .' >&2
exit 1
fi
CLIENT_LIST=$(curl -sS -G "${KEYCLOAK_URL}/admin/realms/${REALM}/clients" \
-H "Authorization: Bearer ${TOKEN}" \
--data-urlencode "clientId=${CLIENT_ID}")
INTERNAL_ID=$(echo "$CLIENT_LIST" | jq -r '.[0].id // empty')
if [ -z "$INTERNAL_ID" ] || [ "$INTERNAL_ID" = "null" ]; then
echo "No client with clientId=${CLIENT_ID} in realm ${REALM}." >&2
exit 1
fi
FULL=$(curl -sS "${KEYCLOAK_URL}/admin/realms/${REALM}/clients/${INTERNAL_ID}" \
-H "Authorization: Bearer ${TOKEN}")
DESIRED_REDIRECTS='[
"https://portal.sankofa.nexus/*",
"https://portal.sankofa.nexus",
"https://admin.sankofa.nexus/*",
"https://admin.sankofa.nexus"
]'
DESIRED_ORIGINS='[
"https://portal.sankofa.nexus",
"https://admin.sankofa.nexus"
]'
MERGED=$(echo "$FULL" | jq --argjson dr "$DESIRED_REDIRECTS" --argjson wo "$DESIRED_ORIGINS" '
.redirectUris = ((.redirectUris // []) + $dr | unique) |
.webOrigins = ((.webOrigins // []) + $wo | unique)
')
if [ "$DRY" = 1 ]; then
echo "[dry-run] Would set client ${CLIENT_ID} (${INTERNAL_ID}) to:"
echo "$MERGED" | jq '{clientId, redirectUris, webOrigins}'
exit 0
fi
HTTP_CODE=$(curl -sS -o /tmp/kc_put_body.txt -w "%{http_code}" -X PUT \
"${KEYCLOAK_URL}/admin/realms/${REALM}/clients/${INTERNAL_ID}" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d "$MERGED")
if [[ "$HTTP_CODE" != "204" && "$HTTP_CODE" != "200" ]]; then
echo "PUT client failed HTTP ${HTTP_CODE}" >&2
cat /tmp/kc_put_body.txt >&2 || true
exit 1
fi
rm -f /tmp/kc_put_body.txt
echo "Updated Keycloak client ${CLIENT_ID}: redirect URIs and web origins merged (portal + admin)."