@tidecloak/create-nextjs 0.12.16 → 0.12.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/template-js-app/init/realm.json +1 -1
- package/template-js-app/init/tcinit.sh +84 -47
- package/template-js-app/package.json +5 -4
- package/template-js-app/package.json.bak +5 -4
- package/template-ts-app/init/realm.json +1 -1
- package/template-ts-app/init/tcinit.sh +84 -47
- package/template-ts-app/package.json +6 -5
- package/template-ts-app/package.json.bak +6 -5
package/package.json
CHANGED
|
@@ -111,7 +111,7 @@
|
|
|
111
111
|
"providerId": "declarative-user-profile",
|
|
112
112
|
"config": {
|
|
113
113
|
"kc.user.profile.config": [
|
|
114
|
-
"{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}]}"
|
|
114
|
+
"{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}],\"unmanagedAttributePolicy\":\"ENABLED\"}"
|
|
115
115
|
]
|
|
116
116
|
}
|
|
117
117
|
}
|
|
@@ -1,9 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
2
3
|
|
|
3
|
-
#
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
5
|
+
# Resolve script directory (run from anywhere)
|
|
6
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
7
|
+
SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd -P)"
|
|
8
|
+
|
|
9
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
10
|
+
# Load overrides from .env.example (CRLF-safe)
|
|
11
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
12
|
+
ENV_FILE="${SCRIPT_DIR}/.env.example"
|
|
13
|
+
if [[ -f "$ENV_FILE" ]]; then
|
|
14
|
+
if grep -q $'\r' "$ENV_FILE"; then
|
|
15
|
+
TMP_ENV="$(mktemp)"
|
|
16
|
+
tr -d '\r' < "$ENV_FILE" > "$TMP_ENV"
|
|
17
|
+
# shellcheck disable=SC1090
|
|
18
|
+
source "$TMP_ENV"
|
|
19
|
+
rm -f "$TMP_ENV"
|
|
20
|
+
else
|
|
21
|
+
# shellcheck disable=SC1090
|
|
22
|
+
source "$ENV_FILE"
|
|
23
|
+
fi
|
|
7
24
|
fi
|
|
8
25
|
|
|
9
26
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -11,23 +28,49 @@ fi
|
|
|
11
28
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
12
29
|
TIDECLOAK_LOCAL_URL="${TIDECLOAK_LOCAL_URL:-http://localhost:8080}"
|
|
13
30
|
CLIENT_APP_URL="${CLIENT_APP_URL:-http://localhost:3000}"
|
|
14
|
-
|
|
15
|
-
ADAPTER_OUTPUT_PATH="${ADAPTER_OUTPUT_PATH:-./tidecloak.json}"
|
|
31
|
+
ADAPTER_OUTPUT_PATH="${ADAPTER_OUTPUT_PATH:-${SCRIPT_DIR}/tidecloak.json}"
|
|
16
32
|
NEW_REALM_NAME="${NEW_REALM_NAME:-nextjs-test}"
|
|
17
|
-
REALM_MGMT_CLIENT_ID="realm-management"
|
|
18
|
-
ADMIN_ROLE_NAME="tide-realm-admin"
|
|
33
|
+
REALM_MGMT_CLIENT_ID="${REALM_MGMT_CLIENT_ID:-realm-management}"
|
|
34
|
+
ADMIN_ROLE_NAME="${ADMIN_ROLE_NAME:-tide-realm-admin}"
|
|
19
35
|
KC_USER="${KC_USER:-admin}"
|
|
20
36
|
KC_PASSWORD="${KC_PASSWORD:-password}"
|
|
21
37
|
CLIENT_NAME="${CLIENT_NAME:-myclient}"
|
|
22
38
|
|
|
23
39
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
24
|
-
#
|
|
40
|
+
# Find realm.json robustly
|
|
41
|
+
# Priority: env → same dir → parent → current working dir
|
|
25
42
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
43
|
+
CANDIDATES=()
|
|
44
|
+
[[ "${REALM_JSON_PATH:-}" != "" ]] && CANDIDATES+=("${REALM_JSON_PATH}")
|
|
45
|
+
CANDIDATES+=("${SCRIPT_DIR}/realm.json" "${SCRIPT_DIR}/../realm.json" "$(pwd)/realm.json")
|
|
46
|
+
|
|
47
|
+
REALM_JSON_PATH=""
|
|
48
|
+
for p in "${CANDIDATES[@]}"; do
|
|
49
|
+
if [[ -f "$p" ]]; then REALM_JSON_PATH="$p"; break; fi
|
|
50
|
+
done
|
|
51
|
+
|
|
52
|
+
echo "🔍 realm.json search candidates:"
|
|
53
|
+
for p in "${CANDIDATES[@]}"; do echo " - $p"; done
|
|
54
|
+
|
|
55
|
+
if [[ -z "${REALM_JSON_PATH}" ]]; then
|
|
56
|
+
echo "❌ Could not find realm.json in the checked locations above." >&2
|
|
57
|
+
echo " Put realm.json next to the script: ${SCRIPT_DIR}/realm.json" >&2
|
|
58
|
+
echo " OR run with: REALM_JSON_PATH=/absolute/path/realm.json bash init/tcinit.sh" >&2
|
|
59
|
+
exit 1
|
|
30
60
|
fi
|
|
61
|
+
echo "✅ Using realm.json: ${REALM_JSON_PATH}"
|
|
62
|
+
|
|
63
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
64
|
+
# Dependency checks
|
|
65
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
66
|
+
need_cmd() { command -v "$1" >/dev/null 2>&1 || { echo "❌ Missing dependency: $1" >&2; exit 1; }; }
|
|
67
|
+
need_cmd curl
|
|
68
|
+
need_cmd jq
|
|
69
|
+
need_cmd sed
|
|
70
|
+
need_cmd mktemp
|
|
71
|
+
|
|
72
|
+
# sed -i portability
|
|
73
|
+
if sed --version >/dev/null 2>&1; then SED_INPLACE=(-i); else SED_INPLACE=(-i ''); fi
|
|
31
74
|
|
|
32
75
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
33
76
|
# Helper: grab an admin token
|
|
@@ -42,19 +85,28 @@ get_admin_token() {
|
|
|
42
85
|
| jq -r .access_token
|
|
43
86
|
}
|
|
44
87
|
|
|
88
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
89
|
+
# Cleanup handler
|
|
90
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
91
|
+
TMP_REALM_JSON=""
|
|
92
|
+
cleanup() {
|
|
93
|
+
[[ -n "${TMP_REALM_JSON}" && -f "${TMP_REALM_JSON}" ]] && rm -f "${TMP_REALM_JSON}" || true
|
|
94
|
+
[[ -f "${SCRIPT_DIR}/.realm_name" ]] && rm -f "${SCRIPT_DIR}/.realm_name" || true
|
|
95
|
+
}
|
|
96
|
+
trap cleanup EXIT
|
|
97
|
+
|
|
45
98
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
46
99
|
# Step 1: prepare realm JSON
|
|
47
100
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
48
101
|
REALM_NAME="${NEW_REALM_NAME}"
|
|
49
|
-
echo "${REALM_NAME}" > "
|
|
102
|
+
echo "${REALM_NAME}" > "${SCRIPT_DIR}/.realm_name"
|
|
50
103
|
|
|
51
104
|
TMP_REALM_JSON="$(mktemp)"
|
|
52
105
|
cp "${REALM_JSON_PATH}" "${TMP_REALM_JSON}"
|
|
53
106
|
|
|
54
|
-
# replace placeholders
|
|
55
107
|
sed "${SED_INPLACE[@]}" "s|http://localhost:3000|${CLIENT_APP_URL}|g" "${TMP_REALM_JSON}"
|
|
56
|
-
sed "${SED_INPLACE[@]}" "s|nextjs-test|${REALM_NAME}|g"
|
|
57
|
-
sed "${SED_INPLACE[@]}" "s|myclient|${CLIENT_NAME}|g"
|
|
108
|
+
sed "${SED_INPLACE[@]}" "s|nextjs-test|${REALM_NAME}|g" "${TMP_REALM_JSON}"
|
|
109
|
+
sed "${SED_INPLACE[@]}" "s|myclient|${CLIENT_NAME}|g" "${TMP_REALM_JSON}"
|
|
58
110
|
|
|
59
111
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
60
112
|
# Step 2: create realm (allow 409 if already exists)
|
|
@@ -80,17 +132,15 @@ fi
|
|
|
80
132
|
TOKEN="$(get_admin_token)"
|
|
81
133
|
echo "🔐 Initializing Tide realm + IGA..."
|
|
82
134
|
|
|
83
|
-
|
|
135
|
+
curl -s -X POST "${TIDECLOAK_LOCAL_URL}/admin/realms/${REALM_NAME}/vendorResources/setUpTideRealm" \
|
|
84
136
|
-H "Authorization: Bearer ${TOKEN}" \
|
|
85
137
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
|
86
|
-
--data-urlencode "email=email@tide.org"
|
|
138
|
+
--data-urlencode "email=email@tide.org" >/dev/null
|
|
87
139
|
|
|
88
|
-
# toggle IGA
|
|
89
140
|
curl -s -X POST "${TIDECLOAK_LOCAL_URL}/admin/realms/${REALM_NAME}/tide-admin/toggle-iga" \
|
|
90
141
|
-H "Authorization: Bearer ${TOKEN}" \
|
|
91
142
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
|
92
|
-
--data-urlencode "isIGAEnabled=true"
|
|
93
|
-
> /dev/null
|
|
143
|
+
--data-urlencode "isIGAEnabled=true" >/dev/null
|
|
94
144
|
|
|
95
145
|
echo "✅ Tide realm + IGA done."
|
|
96
146
|
|
|
@@ -103,7 +153,7 @@ approve_and_commit() {
|
|
|
103
153
|
TOKEN="$(get_admin_token)"
|
|
104
154
|
curl -s -X GET "${TIDECLOAK_LOCAL_URL}/admin/realms/${REALM_NAME}/tide-admin/change-set/${TYPE}/requests" \
|
|
105
155
|
-H "Authorization: Bearer ${TOKEN}" \
|
|
106
|
-
| jq -c '.[]' | while read -r req; do
|
|
156
|
+
| jq -c '.[]' | while IFS= read -r req; do
|
|
107
157
|
payload=$(jq -n \
|
|
108
158
|
--arg id "$(jq -r .draftRecordId <<< "${req}")" \
|
|
109
159
|
--arg cst "$(jq -r .changeSetType <<< "${req}")" \
|
|
@@ -113,14 +163,12 @@ approve_and_commit() {
|
|
|
113
163
|
curl -s -X POST "${TIDECLOAK_LOCAL_URL}/admin/realms/${REALM_NAME}/tide-admin/change-set/sign" \
|
|
114
164
|
-H "Authorization: Bearer ${TOKEN}" \
|
|
115
165
|
-H "Content-Type: application/json" \
|
|
116
|
-
-d "${payload}"
|
|
117
|
-
> /dev/null
|
|
166
|
+
-d "${payload}" >/dev/null
|
|
118
167
|
|
|
119
168
|
curl -s -X POST "${TIDECLOAK_LOCAL_URL}/admin/realms/${REALM_NAME}/tide-admin/change-set/commit" \
|
|
120
169
|
-H "Authorization: Bearer ${TOKEN}" \
|
|
121
170
|
-H "Content-Type: application/json" \
|
|
122
|
-
-d "${payload}"
|
|
123
|
-
> /dev/null
|
|
171
|
+
-d "${payload}" >/dev/null
|
|
124
172
|
done
|
|
125
173
|
echo "✅ ${TYPE^} change-sets done."
|
|
126
174
|
}
|
|
@@ -134,18 +182,15 @@ echo "👤 Creating new admin user..."
|
|
|
134
182
|
curl -s -X POST "${TIDECLOAK_LOCAL_URL}/admin/realms/${REALM_NAME}/users" \
|
|
135
183
|
-H "Authorization: Bearer ${TOKEN}" \
|
|
136
184
|
-H "Content-Type: application/json" \
|
|
137
|
-
-d '{"username":"admin","email":"admin@tidecloak.com","firstName":"admin","lastName":"user","enabled":true}'
|
|
138
|
-
> /dev/null
|
|
185
|
+
-d '{"username":"admin","email":"admin@tidecloak.com","firstName":"admin","lastName":"user","enabled":true}' >/dev/null || true
|
|
139
186
|
|
|
140
187
|
USER_ID=$(curl -s -X GET \
|
|
141
188
|
"${TIDECLOAK_LOCAL_URL}/admin/realms/${REALM_NAME}/users?username=admin" \
|
|
142
|
-
-H "Authorization: Bearer ${TOKEN}"
|
|
143
|
-
| jq -r '.[0].id')
|
|
189
|
+
-H "Authorization: Bearer ${TOKEN}" | jq -r '.[0].id')
|
|
144
190
|
|
|
145
191
|
CLIENT_UUID=$(curl -s -X GET \
|
|
146
192
|
"${TIDECLOAK_LOCAL_URL}/admin/realms/${REALM_NAME}/clients?clientId=${REALM_MGMT_CLIENT_ID}" \
|
|
147
|
-
-H "Authorization: Bearer ${TOKEN}"
|
|
148
|
-
| jq -r '.[0].id')
|
|
193
|
+
-H "Authorization: Bearer ${TOKEN}" | jq -r '.[0].id')
|
|
149
194
|
|
|
150
195
|
ROLE_JSON=$(curl -s -X GET \
|
|
151
196
|
"${TIDECLOAK_LOCAL_URL}/admin/realms/${REALM_NAME}/clients/${CLIENT_UUID}/roles/${ADMIN_ROLE_NAME}" \
|
|
@@ -154,8 +199,7 @@ ROLE_JSON=$(curl -s -X GET \
|
|
|
154
199
|
curl -s -X POST "${TIDECLOAK_LOCAL_URL}/admin/realms/${REALM_NAME}/users/${USER_ID}/role-mappings/clients/${CLIENT_UUID}" \
|
|
155
200
|
-H "Authorization: Bearer ${TOKEN}" \
|
|
156
201
|
-H "Content-Type: application/json" \
|
|
157
|
-
-d "[${ROLE_JSON}]"
|
|
158
|
-
> /dev/null
|
|
202
|
+
-d "[${ROLE_JSON}]" >/dev/null
|
|
159
203
|
|
|
160
204
|
echo "✅ Admin user & role done."
|
|
161
205
|
|
|
@@ -216,32 +260,25 @@ UPDATED_JSON=$(jq --arg d "${CLIENT_APP_URL}" '.config.CustomAdminUIDomain = $d'
|
|
|
216
260
|
curl -s -X PUT "${TIDECLOAK_LOCAL_URL}/admin/realms/${REALM_NAME}/identity-provider/instances/tide" \
|
|
217
261
|
-H "Authorization: Bearer ${TOKEN}" \
|
|
218
262
|
-H "Content-Type: application/json" \
|
|
219
|
-
-d "${UPDATED_JSON}"
|
|
220
|
-
> /dev/null
|
|
263
|
+
-d "${UPDATED_JSON}" >/dev/null
|
|
221
264
|
|
|
222
265
|
curl -s -X POST "${TIDECLOAK_LOCAL_URL}/admin/realms/${REALM_NAME}/vendorResources/sign-idp-settings" \
|
|
223
|
-
-H "Authorization: Bearer ${TOKEN}"
|
|
224
|
-
> /dev/null
|
|
266
|
+
-H "Authorization: Bearer ${TOKEN}" >/dev/null
|
|
225
267
|
|
|
226
268
|
echo "✅ CustomAdminUIDomain updated + signed."
|
|
227
269
|
|
|
228
|
-
|
|
229
270
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
230
|
-
# Step 7: fetch adapter config
|
|
271
|
+
# Step 7: fetch adapter config
|
|
231
272
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
232
273
|
TOKEN="$(get_admin_token)"
|
|
233
274
|
echo "📥 Fetching adapter config…"
|
|
234
275
|
CLIENT_UUID=$(curl -s -X GET \
|
|
235
276
|
"${TIDECLOAK_LOCAL_URL}/admin/realms/${REALM_NAME}/clients?clientId=${CLIENT_NAME}" \
|
|
236
|
-
-H "Authorization: Bearer ${TOKEN}"
|
|
237
|
-
| jq -r '.[0].id')
|
|
277
|
+
-H "Authorization: Bearer ${TOKEN}" | jq -r '.[0].id')
|
|
238
278
|
|
|
239
279
|
curl -s -X GET \
|
|
240
280
|
"${TIDECLOAK_LOCAL_URL}/admin/realms/${REALM_NAME}/vendorResources/get-installations-provider?clientId=${CLIENT_UUID}&providerId=keycloak-oidc-keycloak-json" \
|
|
241
|
-
-H "Authorization: Bearer ${TOKEN}"
|
|
242
|
-
> "${ADAPTER_OUTPUT_PATH}"
|
|
281
|
+
-H "Authorization: Bearer ${TOKEN}" > "${ADAPTER_OUTPUT_PATH}"
|
|
243
282
|
|
|
244
283
|
echo "✅ Adapter config saved to ${ADAPTER_OUTPUT_PATH}"
|
|
245
|
-
rm -f "${PROJECT_ROOT}/.realm_name" "${TMP_REALM_JSON}"
|
|
246
|
-
|
|
247
284
|
echo "🎉 All done!"
|
|
@@ -9,9 +9,10 @@
|
|
|
9
9
|
"init": "bash init/tcinit.sh"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
12
|
+
"@tidecloak/nextjs": "^0.12.27",
|
|
13
|
+
"eslint-config-next": "^16.0.1",
|
|
14
|
+
"next": "^16.0.1",
|
|
15
|
+
"react": "^19.2.0",
|
|
16
|
+
"react-dom": "^19.2.0"
|
|
16
17
|
}
|
|
17
18
|
}
|
|
@@ -9,9 +9,10 @@
|
|
|
9
9
|
"init": "bash init/tcinit.sh"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
12
|
+
"@tidecloak/nextjs": "^0.9.12",
|
|
13
|
+
"eslint-config-next": "^16.0.1",
|
|
14
|
+
"next": "^16.0.1",
|
|
15
|
+
"react": "^19.2.0",
|
|
16
|
+
"react-dom": "^19.2.0"
|
|
16
17
|
}
|
|
17
18
|
}
|
|
@@ -111,7 +111,7 @@
|
|
|
111
111
|
"providerId": "declarative-user-profile",
|
|
112
112
|
"config": {
|
|
113
113
|
"kc.user.profile.config": [
|
|
114
|
-
"{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}]}"
|
|
114
|
+
"{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}],\"unmanagedAttributePolicy\":\"ENABLED\"}"
|
|
115
115
|
]
|
|
116
116
|
}
|
|
117
117
|
}
|
|
@@ -1,9 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
2
3
|
|
|
3
|
-
#
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
5
|
+
# Resolve script directory (run from anywhere)
|
|
6
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
7
|
+
SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd -P)"
|
|
8
|
+
|
|
9
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
10
|
+
# Load overrides from .env.example (CRLF-safe)
|
|
11
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
12
|
+
ENV_FILE="${SCRIPT_DIR}/.env.example"
|
|
13
|
+
if [[ -f "$ENV_FILE" ]]; then
|
|
14
|
+
if grep -q $'\r' "$ENV_FILE"; then
|
|
15
|
+
TMP_ENV="$(mktemp)"
|
|
16
|
+
tr -d '\r' < "$ENV_FILE" > "$TMP_ENV"
|
|
17
|
+
# shellcheck disable=SC1090
|
|
18
|
+
source "$TMP_ENV"
|
|
19
|
+
rm -f "$TMP_ENV"
|
|
20
|
+
else
|
|
21
|
+
# shellcheck disable=SC1090
|
|
22
|
+
source "$ENV_FILE"
|
|
23
|
+
fi
|
|
7
24
|
fi
|
|
8
25
|
|
|
9
26
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -11,23 +28,49 @@ fi
|
|
|
11
28
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
12
29
|
TIDECLOAK_LOCAL_URL="${TIDECLOAK_LOCAL_URL:-http://localhost:8080}"
|
|
13
30
|
CLIENT_APP_URL="${CLIENT_APP_URL:-http://localhost:3000}"
|
|
14
|
-
|
|
15
|
-
ADAPTER_OUTPUT_PATH="${ADAPTER_OUTPUT_PATH:-./tidecloak.json}"
|
|
31
|
+
ADAPTER_OUTPUT_PATH="${ADAPTER_OUTPUT_PATH:-${SCRIPT_DIR}/tidecloak.json}"
|
|
16
32
|
NEW_REALM_NAME="${NEW_REALM_NAME:-nextjs-test}"
|
|
17
|
-
REALM_MGMT_CLIENT_ID="realm-management"
|
|
18
|
-
ADMIN_ROLE_NAME="tide-realm-admin"
|
|
33
|
+
REALM_MGMT_CLIENT_ID="${REALM_MGMT_CLIENT_ID:-realm-management}"
|
|
34
|
+
ADMIN_ROLE_NAME="${ADMIN_ROLE_NAME:-tide-realm-admin}"
|
|
19
35
|
KC_USER="${KC_USER:-admin}"
|
|
20
36
|
KC_PASSWORD="${KC_PASSWORD:-password}"
|
|
21
37
|
CLIENT_NAME="${CLIENT_NAME:-myclient}"
|
|
22
38
|
|
|
23
39
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
24
|
-
#
|
|
40
|
+
# Find realm.json robustly
|
|
41
|
+
# Priority: env → same dir → parent → current working dir
|
|
25
42
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
43
|
+
CANDIDATES=()
|
|
44
|
+
[[ "${REALM_JSON_PATH:-}" != "" ]] && CANDIDATES+=("${REALM_JSON_PATH}")
|
|
45
|
+
CANDIDATES+=("${SCRIPT_DIR}/realm.json" "${SCRIPT_DIR}/../realm.json" "$(pwd)/realm.json")
|
|
46
|
+
|
|
47
|
+
REALM_JSON_PATH=""
|
|
48
|
+
for p in "${CANDIDATES[@]}"; do
|
|
49
|
+
if [[ -f "$p" ]]; then REALM_JSON_PATH="$p"; break; fi
|
|
50
|
+
done
|
|
51
|
+
|
|
52
|
+
echo "🔍 realm.json search candidates:"
|
|
53
|
+
for p in "${CANDIDATES[@]}"; do echo " - $p"; done
|
|
54
|
+
|
|
55
|
+
if [[ -z "${REALM_JSON_PATH}" ]]; then
|
|
56
|
+
echo "❌ Could not find realm.json in the checked locations above." >&2
|
|
57
|
+
echo " Put realm.json next to the script: ${SCRIPT_DIR}/realm.json" >&2
|
|
58
|
+
echo " OR run with: REALM_JSON_PATH=/absolute/path/realm.json bash init/tcinit.sh" >&2
|
|
59
|
+
exit 1
|
|
30
60
|
fi
|
|
61
|
+
echo "✅ Using realm.json: ${REALM_JSON_PATH}"
|
|
62
|
+
|
|
63
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
64
|
+
# Dependency checks
|
|
65
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
66
|
+
need_cmd() { command -v "$1" >/dev/null 2>&1 || { echo "❌ Missing dependency: $1" >&2; exit 1; }; }
|
|
67
|
+
need_cmd curl
|
|
68
|
+
need_cmd jq
|
|
69
|
+
need_cmd sed
|
|
70
|
+
need_cmd mktemp
|
|
71
|
+
|
|
72
|
+
# sed -i portability
|
|
73
|
+
if sed --version >/dev/null 2>&1; then SED_INPLACE=(-i); else SED_INPLACE=(-i ''); fi
|
|
31
74
|
|
|
32
75
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
33
76
|
# Helper: grab an admin token
|
|
@@ -42,19 +85,28 @@ get_admin_token() {
|
|
|
42
85
|
| jq -r .access_token
|
|
43
86
|
}
|
|
44
87
|
|
|
88
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
89
|
+
# Cleanup handler
|
|
90
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
91
|
+
TMP_REALM_JSON=""
|
|
92
|
+
cleanup() {
|
|
93
|
+
[[ -n "${TMP_REALM_JSON}" && -f "${TMP_REALM_JSON}" ]] && rm -f "${TMP_REALM_JSON}" || true
|
|
94
|
+
[[ -f "${SCRIPT_DIR}/.realm_name" ]] && rm -f "${SCRIPT_DIR}/.realm_name" || true
|
|
95
|
+
}
|
|
96
|
+
trap cleanup EXIT
|
|
97
|
+
|
|
45
98
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
46
99
|
# Step 1: prepare realm JSON
|
|
47
100
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
48
101
|
REALM_NAME="${NEW_REALM_NAME}"
|
|
49
|
-
echo "${REALM_NAME}" > "
|
|
102
|
+
echo "${REALM_NAME}" > "${SCRIPT_DIR}/.realm_name"
|
|
50
103
|
|
|
51
104
|
TMP_REALM_JSON="$(mktemp)"
|
|
52
105
|
cp "${REALM_JSON_PATH}" "${TMP_REALM_JSON}"
|
|
53
106
|
|
|
54
|
-
# replace placeholders
|
|
55
107
|
sed "${SED_INPLACE[@]}" "s|http://localhost:3000|${CLIENT_APP_URL}|g" "${TMP_REALM_JSON}"
|
|
56
|
-
sed "${SED_INPLACE[@]}" "s|nextjs-test|${REALM_NAME}|g"
|
|
57
|
-
sed "${SED_INPLACE[@]}" "s|myclient|${CLIENT_NAME}|g"
|
|
108
|
+
sed "${SED_INPLACE[@]}" "s|nextjs-test|${REALM_NAME}|g" "${TMP_REALM_JSON}"
|
|
109
|
+
sed "${SED_INPLACE[@]}" "s|myclient|${CLIENT_NAME}|g" "${TMP_REALM_JSON}"
|
|
58
110
|
|
|
59
111
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
60
112
|
# Step 2: create realm (allow 409 if already exists)
|
|
@@ -80,17 +132,15 @@ fi
|
|
|
80
132
|
TOKEN="$(get_admin_token)"
|
|
81
133
|
echo "🔐 Initializing Tide realm + IGA..."
|
|
82
134
|
|
|
83
|
-
|
|
135
|
+
curl -s -X POST "${TIDECLOAK_LOCAL_URL}/admin/realms/${REALM_NAME}/vendorResources/setUpTideRealm" \
|
|
84
136
|
-H "Authorization: Bearer ${TOKEN}" \
|
|
85
137
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
|
86
|
-
--data-urlencode "email=email@tide.org"
|
|
138
|
+
--data-urlencode "email=email@tide.org" >/dev/null
|
|
87
139
|
|
|
88
|
-
# toggle IGA
|
|
89
140
|
curl -s -X POST "${TIDECLOAK_LOCAL_URL}/admin/realms/${REALM_NAME}/tide-admin/toggle-iga" \
|
|
90
141
|
-H "Authorization: Bearer ${TOKEN}" \
|
|
91
142
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
|
92
|
-
--data-urlencode "isIGAEnabled=true"
|
|
93
|
-
> /dev/null
|
|
143
|
+
--data-urlencode "isIGAEnabled=true" >/dev/null
|
|
94
144
|
|
|
95
145
|
echo "✅ Tide realm + IGA done."
|
|
96
146
|
|
|
@@ -103,7 +153,7 @@ approve_and_commit() {
|
|
|
103
153
|
TOKEN="$(get_admin_token)"
|
|
104
154
|
curl -s -X GET "${TIDECLOAK_LOCAL_URL}/admin/realms/${REALM_NAME}/tide-admin/change-set/${TYPE}/requests" \
|
|
105
155
|
-H "Authorization: Bearer ${TOKEN}" \
|
|
106
|
-
| jq -c '.[]' | while read -r req; do
|
|
156
|
+
| jq -c '.[]' | while IFS= read -r req; do
|
|
107
157
|
payload=$(jq -n \
|
|
108
158
|
--arg id "$(jq -r .draftRecordId <<< "${req}")" \
|
|
109
159
|
--arg cst "$(jq -r .changeSetType <<< "${req}")" \
|
|
@@ -113,14 +163,12 @@ approve_and_commit() {
|
|
|
113
163
|
curl -s -X POST "${TIDECLOAK_LOCAL_URL}/admin/realms/${REALM_NAME}/tide-admin/change-set/sign" \
|
|
114
164
|
-H "Authorization: Bearer ${TOKEN}" \
|
|
115
165
|
-H "Content-Type: application/json" \
|
|
116
|
-
-d "${payload}"
|
|
117
|
-
> /dev/null
|
|
166
|
+
-d "${payload}" >/dev/null
|
|
118
167
|
|
|
119
168
|
curl -s -X POST "${TIDECLOAK_LOCAL_URL}/admin/realms/${REALM_NAME}/tide-admin/change-set/commit" \
|
|
120
169
|
-H "Authorization: Bearer ${TOKEN}" \
|
|
121
170
|
-H "Content-Type: application/json" \
|
|
122
|
-
-d "${payload}"
|
|
123
|
-
> /dev/null
|
|
171
|
+
-d "${payload}" >/dev/null
|
|
124
172
|
done
|
|
125
173
|
echo "✅ ${TYPE^} change-sets done."
|
|
126
174
|
}
|
|
@@ -134,18 +182,15 @@ echo "👤 Creating new admin user..."
|
|
|
134
182
|
curl -s -X POST "${TIDECLOAK_LOCAL_URL}/admin/realms/${REALM_NAME}/users" \
|
|
135
183
|
-H "Authorization: Bearer ${TOKEN}" \
|
|
136
184
|
-H "Content-Type: application/json" \
|
|
137
|
-
-d '{"username":"admin","email":"admin@tidecloak.com","firstName":"admin","lastName":"user","enabled":true}'
|
|
138
|
-
> /dev/null
|
|
185
|
+
-d '{"username":"admin","email":"admin@tidecloak.com","firstName":"admin","lastName":"user","enabled":true}' >/dev/null || true
|
|
139
186
|
|
|
140
187
|
USER_ID=$(curl -s -X GET \
|
|
141
188
|
"${TIDECLOAK_LOCAL_URL}/admin/realms/${REALM_NAME}/users?username=admin" \
|
|
142
|
-
-H "Authorization: Bearer ${TOKEN}"
|
|
143
|
-
| jq -r '.[0].id')
|
|
189
|
+
-H "Authorization: Bearer ${TOKEN}" | jq -r '.[0].id')
|
|
144
190
|
|
|
145
191
|
CLIENT_UUID=$(curl -s -X GET \
|
|
146
192
|
"${TIDECLOAK_LOCAL_URL}/admin/realms/${REALM_NAME}/clients?clientId=${REALM_MGMT_CLIENT_ID}" \
|
|
147
|
-
-H "Authorization: Bearer ${TOKEN}"
|
|
148
|
-
| jq -r '.[0].id')
|
|
193
|
+
-H "Authorization: Bearer ${TOKEN}" | jq -r '.[0].id')
|
|
149
194
|
|
|
150
195
|
ROLE_JSON=$(curl -s -X GET \
|
|
151
196
|
"${TIDECLOAK_LOCAL_URL}/admin/realms/${REALM_NAME}/clients/${CLIENT_UUID}/roles/${ADMIN_ROLE_NAME}" \
|
|
@@ -154,8 +199,7 @@ ROLE_JSON=$(curl -s -X GET \
|
|
|
154
199
|
curl -s -X POST "${TIDECLOAK_LOCAL_URL}/admin/realms/${REALM_NAME}/users/${USER_ID}/role-mappings/clients/${CLIENT_UUID}" \
|
|
155
200
|
-H "Authorization: Bearer ${TOKEN}" \
|
|
156
201
|
-H "Content-Type: application/json" \
|
|
157
|
-
-d "[${ROLE_JSON}]"
|
|
158
|
-
> /dev/null
|
|
202
|
+
-d "[${ROLE_JSON}]" >/dev/null
|
|
159
203
|
|
|
160
204
|
echo "✅ Admin user & role done."
|
|
161
205
|
|
|
@@ -216,32 +260,25 @@ UPDATED_JSON=$(jq --arg d "${CLIENT_APP_URL}" '.config.CustomAdminUIDomain = $d'
|
|
|
216
260
|
curl -s -X PUT "${TIDECLOAK_LOCAL_URL}/admin/realms/${REALM_NAME}/identity-provider/instances/tide" \
|
|
217
261
|
-H "Authorization: Bearer ${TOKEN}" \
|
|
218
262
|
-H "Content-Type: application/json" \
|
|
219
|
-
-d "${UPDATED_JSON}"
|
|
220
|
-
> /dev/null
|
|
263
|
+
-d "${UPDATED_JSON}" >/dev/null
|
|
221
264
|
|
|
222
265
|
curl -s -X POST "${TIDECLOAK_LOCAL_URL}/admin/realms/${REALM_NAME}/vendorResources/sign-idp-settings" \
|
|
223
|
-
-H "Authorization: Bearer ${TOKEN}"
|
|
224
|
-
> /dev/null
|
|
266
|
+
-H "Authorization: Bearer ${TOKEN}" >/dev/null
|
|
225
267
|
|
|
226
268
|
echo "✅ CustomAdminUIDomain updated + signed."
|
|
227
269
|
|
|
228
|
-
|
|
229
270
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
230
|
-
# Step 7: fetch adapter config
|
|
271
|
+
# Step 7: fetch adapter config
|
|
231
272
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
232
273
|
TOKEN="$(get_admin_token)"
|
|
233
274
|
echo "📥 Fetching adapter config…"
|
|
234
275
|
CLIENT_UUID=$(curl -s -X GET \
|
|
235
276
|
"${TIDECLOAK_LOCAL_URL}/admin/realms/${REALM_NAME}/clients?clientId=${CLIENT_NAME}" \
|
|
236
|
-
-H "Authorization: Bearer ${TOKEN}"
|
|
237
|
-
| jq -r '.[0].id')
|
|
277
|
+
-H "Authorization: Bearer ${TOKEN}" | jq -r '.[0].id')
|
|
238
278
|
|
|
239
279
|
curl -s -X GET \
|
|
240
280
|
"${TIDECLOAK_LOCAL_URL}/admin/realms/${REALM_NAME}/vendorResources/get-installations-provider?clientId=${CLIENT_UUID}&providerId=keycloak-oidc-keycloak-json" \
|
|
241
|
-
-H "Authorization: Bearer ${TOKEN}"
|
|
242
|
-
> "${ADAPTER_OUTPUT_PATH}"
|
|
281
|
+
-H "Authorization: Bearer ${TOKEN}" > "${ADAPTER_OUTPUT_PATH}"
|
|
243
282
|
|
|
244
283
|
echo "✅ Adapter config saved to ${ADAPTER_OUTPUT_PATH}"
|
|
245
|
-
rm -f "${PROJECT_ROOT}/.realm_name" "${TMP_REALM_JSON}"
|
|
246
|
-
|
|
247
284
|
echo "🎉 All done!"
|
|
@@ -9,12 +9,13 @@
|
|
|
9
9
|
"init": "bash init/tcinit.sh"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
12
|
+
"@tidecloak/nextjs": "^0.12.27",
|
|
13
|
+
"eslint-config-next": "^16.0.1",
|
|
14
|
+
"next": "^16.0.1",
|
|
15
|
+
"react": "^19.2.0",
|
|
16
|
+
"react-dom": "^19.2.0"
|
|
16
17
|
},
|
|
17
|
-
|
|
18
|
+
"devDependencies": {
|
|
18
19
|
"@types/node": "24.0.13",
|
|
19
20
|
"@types/react": "19.1.8",
|
|
20
21
|
"typescript": "5.8.3"
|
|
@@ -9,12 +9,13 @@
|
|
|
9
9
|
"init": "bash init/tcinit.sh"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
12
|
+
"@tidecloak/nextjs": "^0.9.12",
|
|
13
|
+
"eslint-config-next": "^16.0.1",
|
|
14
|
+
"next": "^16.0.1",
|
|
15
|
+
"react": "^19.2.0",
|
|
16
|
+
"react-dom": "^19.2.0"
|
|
16
17
|
},
|
|
17
|
-
|
|
18
|
+
"devDependencies": {
|
|
18
19
|
"@types/node": "24.0.13",
|
|
19
20
|
"@types/react": "19.1.8",
|
|
20
21
|
"typescript": "5.8.3"
|