fix: use BOOTSTRAP_LOCAL flag to skip Host headers in bootstrap
When running inside the Logto container (BOOTSTRAP_LOCAL=true), the bootstrap script skips Host and X-Forwarded-Proto headers on all curl calls. This avoids issuer mismatches when Logto runs with localhost endpoints during bootstrap mode. PUBLIC_HOST/PUBLIC_PROTOCOL remain unchanged so redirect URIs are generated with the correct public values. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -32,10 +32,12 @@ for i in $(seq 1 120); do
|
|||||||
sleep 1
|
sleep 1
|
||||||
done
|
done
|
||||||
|
|
||||||
# Run bootstrap if not already done — use localhost since we're inside the container
|
# Run bootstrap — use localhost endpoints, skip Host headers (BOOTSTRAP_LOCAL flag)
|
||||||
|
# PUBLIC_HOST and PUBLIC_PROTOCOL stay real for redirect URI generation
|
||||||
BOOTSTRAP_FILE="/data/logto-bootstrap.json"
|
BOOTSTRAP_FILE="/data/logto-bootstrap.json"
|
||||||
export LOGTO_ENDPOINT="http://localhost:3001"
|
export LOGTO_ENDPOINT="http://localhost:3001"
|
||||||
export LOGTO_ADMIN_ENDPOINT="http://localhost:3002"
|
export LOGTO_ADMIN_ENDPOINT="http://localhost:3002"
|
||||||
|
export BOOTSTRAP_LOCAL="true"
|
||||||
|
|
||||||
if [ -f "$BOOTSTRAP_FILE" ]; then
|
if [ -f "$BOOTSTRAP_FILE" ]; then
|
||||||
CACHED_SECRET=$(jq -r '.m2mClientSecret // empty' "$BOOTSTRAP_FILE" 2>/dev/null)
|
CACHED_SECRET=$(jq -r '.m2mClientSecret // empty' "$BOOTSTRAP_FILE" 2>/dev/null)
|
||||||
|
|||||||
@@ -47,6 +47,16 @@ TRAD_POST_LOGOUT_URIS="[\"${PROTO}://${HOST}\",\"${PROTO}://${HOST}/server\",\"$
|
|||||||
log() { echo "[bootstrap] $1"; }
|
log() { echo "[bootstrap] $1"; }
|
||||||
pgpass() { PGPASSWORD="${PG_PASSWORD:-cameleer_dev}"; export PGPASSWORD; }
|
pgpass() { PGPASSWORD="${PG_PASSWORD:-cameleer_dev}"; export PGPASSWORD; }
|
||||||
|
|
||||||
|
# When BOOTSTRAP_LOCAL=true (running inside Logto container with localhost endpoints),
|
||||||
|
# skip Host/X-Forwarded-Proto headers — they cause issuer mismatches with localhost
|
||||||
|
if [ "$BOOTSTRAP_LOCAL" = "true" ]; then
|
||||||
|
HOST_ARGS=""
|
||||||
|
ADMIN_HOST_ARGS=""
|
||||||
|
else
|
||||||
|
HOST_ARGS="-H Host:${HOST}"
|
||||||
|
ADMIN_HOST_ARGS="-H Host:${HOST}:3002 -H X-Forwarded-Proto:https"
|
||||||
|
fi
|
||||||
|
|
||||||
# Install jq + curl if not already available (deps are baked into cameleer-logto image)
|
# Install jq + curl if not already available (deps are baked into cameleer-logto image)
|
||||||
if ! command -v jq >/dev/null 2>&1 || ! command -v curl >/dev/null 2>&1; then
|
if ! command -v jq >/dev/null 2>&1 || ! command -v curl >/dev/null 2>&1; then
|
||||||
if command -v apk >/dev/null 2>&1; then
|
if command -v apk >/dev/null 2>&1; then
|
||||||
@@ -97,15 +107,14 @@ M_DEFAULT_SECRET=$(psql -h "$PG_HOST" -U "$PG_USER" -d "$PG_DB_LOGTO" -t -A -c \
|
|||||||
get_admin_token() {
|
get_admin_token() {
|
||||||
curl -s -X POST "${LOGTO_ADMIN_ENDPOINT}/oidc/token" \
|
curl -s -X POST "${LOGTO_ADMIN_ENDPOINT}/oidc/token" \
|
||||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||||
-H "Host: ${HOST}:3002" \
|
$ADMIN_HOST_ARGS \
|
||||||
-H "X-Forwarded-Proto: https" \
|
|
||||||
-d "grant_type=client_credentials&client_id=${1}&client_secret=${2}&resource=${MGMT_API_RESOURCE}&scope=all"
|
-d "grant_type=client_credentials&client_id=${1}&client_secret=${2}&resource=${MGMT_API_RESOURCE}&scope=all"
|
||||||
}
|
}
|
||||||
|
|
||||||
get_default_token() {
|
get_default_token() {
|
||||||
curl -s -X POST "${LOGTO_ENDPOINT}/oidc/token" \
|
curl -s -X POST "${LOGTO_ENDPOINT}/oidc/token" \
|
||||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||||
-H "Host: ${HOST}" \
|
$HOST_ARGS \
|
||||||
-d "grant_type=client_credentials&client_id=${1}&client_secret=${2}&resource=${MGMT_API_RESOURCE}&scope=all"
|
-d "grant_type=client_credentials&client_id=${1}&client_secret=${2}&resource=${MGMT_API_RESOURCE}&scope=all"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,7 +127,7 @@ log "Got Management API token."
|
|||||||
# Verify Management API is fully ready (Logto may still be initializing internally)
|
# Verify Management API is fully ready (Logto may still be initializing internally)
|
||||||
log "Verifying Management API is responsive..."
|
log "Verifying Management API is responsive..."
|
||||||
for i in $(seq 1 30); do
|
for i in $(seq 1 30); do
|
||||||
VERIFY_RESPONSE=$(curl -s -H "Authorization: Bearer $TOKEN" -H "Host: ${HOST}" "${LOGTO_ENDPOINT}/api/roles" 2>/dev/null)
|
VERIFY_RESPONSE=$(curl -s -H "Authorization: Bearer $TOKEN" $HOST_ARGS "${LOGTO_ENDPOINT}/api/roles" 2>/dev/null)
|
||||||
if echo "$VERIFY_RESPONSE" | jq -e 'type == "array"' >/dev/null 2>&1; then
|
if echo "$VERIFY_RESPONSE" | jq -e 'type == "array"' >/dev/null 2>&1; then
|
||||||
log "Management API is ready."
|
log "Management API is ready."
|
||||||
break
|
break
|
||||||
@@ -129,21 +138,21 @@ done
|
|||||||
|
|
||||||
# --- Helper: Logto API calls ---
|
# --- Helper: Logto API calls ---
|
||||||
api_get() {
|
api_get() {
|
||||||
curl -s -H "Authorization: Bearer $TOKEN" -H "Host: ${HOST}" "${LOGTO_ENDPOINT}${1}" 2>/dev/null || echo "[]"
|
curl -s -H "Authorization: Bearer $TOKEN" $HOST_ARGS "${LOGTO_ENDPOINT}${1}" 2>/dev/null || echo "[]"
|
||||||
}
|
}
|
||||||
api_post() {
|
api_post() {
|
||||||
curl -s -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -H "Host: ${HOST}" \
|
curl -s -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" $HOST_ARGS \
|
||||||
-d "$2" "${LOGTO_ENDPOINT}${1}" 2>/dev/null || true
|
-d "$2" "${LOGTO_ENDPOINT}${1}" 2>/dev/null || true
|
||||||
}
|
}
|
||||||
api_put() {
|
api_put() {
|
||||||
curl -s -X PUT -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -H "Host: ${HOST}" \
|
curl -s -X PUT -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" $HOST_ARGS \
|
||||||
-d "$2" "${LOGTO_ENDPOINT}${1}" 2>/dev/null || true
|
-d "$2" "${LOGTO_ENDPOINT}${1}" 2>/dev/null || true
|
||||||
}
|
}
|
||||||
api_delete() {
|
api_delete() {
|
||||||
curl -s -X DELETE -H "Authorization: Bearer $TOKEN" -H "Host: ${HOST}" "${LOGTO_ENDPOINT}${1}" 2>/dev/null || true
|
curl -s -X DELETE -H "Authorization: Bearer $TOKEN" $HOST_ARGS "${LOGTO_ENDPOINT}${1}" 2>/dev/null || true
|
||||||
}
|
}
|
||||||
api_patch() {
|
api_patch() {
|
||||||
curl -s -X PATCH -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -H "Host: ${HOST}" \
|
curl -s -X PATCH -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" $HOST_ARGS \
|
||||||
-d "$2" "${LOGTO_ENDPOINT}${1}" 2>/dev/null || true
|
-d "$2" "${LOGTO_ENDPOINT}${1}" 2>/dev/null || true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -416,8 +425,7 @@ if [ -z "$M_ADMIN_SECRET" ]; then
|
|||||||
else
|
else
|
||||||
ADMIN_TOKEN_RESPONSE=$(curl -s -X POST "${LOGTO_ADMIN_ENDPOINT}/oidc/token" \
|
ADMIN_TOKEN_RESPONSE=$(curl -s -X POST "${LOGTO_ADMIN_ENDPOINT}/oidc/token" \
|
||||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||||
-H "Host: ${HOST}:3002" \
|
$ADMIN_HOST_ARGS \
|
||||||
-H "X-Forwarded-Proto: https" \
|
|
||||||
-d "grant_type=client_credentials&client_id=m-admin&client_secret=${M_ADMIN_SECRET}&resource=${ADMIN_MGMT_RESOURCE}&scope=all")
|
-d "grant_type=client_credentials&client_id=m-admin&client_secret=${M_ADMIN_SECRET}&resource=${ADMIN_MGMT_RESOURCE}&scope=all")
|
||||||
ADMIN_TOKEN=$(echo "$ADMIN_TOKEN_RESPONSE" | jq -r '.access_token' 2>/dev/null)
|
ADMIN_TOKEN=$(echo "$ADMIN_TOKEN_RESPONSE" | jq -r '.access_token' 2>/dev/null)
|
||||||
|
|
||||||
@@ -429,14 +437,14 @@ else
|
|||||||
|
|
||||||
# Admin-tenant API helpers (port 3002, admin token)
|
# Admin-tenant API helpers (port 3002, admin token)
|
||||||
admin_api_get() {
|
admin_api_get() {
|
||||||
curl -s -H "Authorization: Bearer $ADMIN_TOKEN" -H "Host: ${HOST}:3002" -H "X-Forwarded-Proto: https" "${LOGTO_ADMIN_ENDPOINT}${1}" 2>/dev/null || echo "[]"
|
curl -s -H "Authorization: Bearer $ADMIN_TOKEN" $ADMIN_HOST_ARGS "${LOGTO_ADMIN_ENDPOINT}${1}" 2>/dev/null || echo "[]"
|
||||||
}
|
}
|
||||||
admin_api_post() {
|
admin_api_post() {
|
||||||
curl -s -X POST -H "Authorization: Bearer $ADMIN_TOKEN" -H "Content-Type: application/json" -H "Host: ${HOST}:3002" -H "X-Forwarded-Proto: https" \
|
curl -s -X POST -H "Authorization: Bearer $ADMIN_TOKEN" -H "Content-Type: application/json" $ADMIN_HOST_ARGS \
|
||||||
-d "$2" "${LOGTO_ADMIN_ENDPOINT}${1}" 2>/dev/null || true
|
-d "$2" "${LOGTO_ADMIN_ENDPOINT}${1}" 2>/dev/null || true
|
||||||
}
|
}
|
||||||
admin_api_patch() {
|
admin_api_patch() {
|
||||||
curl -s -X PATCH -H "Authorization: Bearer $ADMIN_TOKEN" -H "Content-Type: application/json" -H "Host: ${HOST}:3002" -H "X-Forwarded-Proto: https" \
|
curl -s -X PATCH -H "Authorization: Bearer $ADMIN_TOKEN" -H "Content-Type: application/json" $ADMIN_HOST_ARGS \
|
||||||
-d "$2" "${LOGTO_ADMIN_ENDPOINT}${1}" 2>/dev/null || true
|
-d "$2" "${LOGTO_ADMIN_ENDPOINT}${1}" 2>/dev/null || true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user