strapi-plugin-keycloak-realm-users 1.0.0 → 1.0.2
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/README.md +239 -336
- package/dist/_chunks/{App-DO6syS77.js → App-Cxl4vy52.js} +45 -34
- package/dist/_chunks/{App-BaKrvCeS.mjs → App-ZmFgfMD9.mjs} +45 -34
- package/dist/_chunks/{index-jTVd7LdQ.mjs → index-BXykyqCE.mjs} +5 -2
- package/dist/_chunks/{index-DwDO4-0C.js → index-_Hrf07zU.js} +5 -2
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/server/index.js +67 -58
- package/dist/server/index.mjs +67 -58
- package/package.json +21 -9
- package/strapi-admin.js +3 -0
- package/strapi-server.js +3 -0
- package/__tests__/constants.test.mjs +0 -207
- package/__tests__/mocks/strapi.mjs +0 -182
- package/__tests__/services/audit-log.test.mjs +0 -283
- package/__tests__/services/keycloak-client.test.mjs +0 -651
- package/__tests__/services/permission.test.mjs +0 -374
- package/__tests__/services/realm.test.mjs +0 -415
- package/__tests__/services/user.test.mjs +0 -487
- package/__tests__/utils/errors.test.mjs +0 -109
- package/admin/src/components/Initializer.jsx +0 -14
- package/admin/src/components/RealmBadge.jsx +0 -17
- package/admin/src/constants.js +0 -14
- package/admin/src/hooks/useAuditLogs.js +0 -142
- package/admin/src/hooks/useKeycloakRoles.js +0 -182
- package/admin/src/hooks/useKeycloakUsers.js +0 -477
- package/admin/src/hooks/useRealmAdmins.js +0 -249
- package/admin/src/hooks/useRealms.js +0 -269
- package/admin/src/index.js +0 -46
- package/admin/src/pages/App.jsx +0 -21
- package/admin/src/pages/AuditPage/index.jsx +0 -213
- package/admin/src/pages/RealmsPage/RealmEditPage.jsx +0 -791
- package/admin/src/pages/RealmsPage/RealmListPage.jsx +0 -231
- package/admin/src/pages/RealmsPage/index.jsx +0 -7
- package/admin/src/pages/UsersPage/UserEditPage.jsx +0 -313
- package/admin/src/pages/UsersPage/UserListPage.jsx +0 -437
- package/admin/src/pages/UsersPage/index.jsx +0 -7
- package/admin/src/pluginId.js +0 -2
- package/admin/src/translations/en.json +0 -77
- package/admin/src/translations/fr.json +0 -77
- package/babel.config.cjs +0 -17
- package/coverage/clover.xml +0 -422
- package/coverage/coverage-final.json +0 -8
- package/coverage/lcov-report/base.css +0 -224
- package/coverage/lcov-report/block-navigation.js +0 -87
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +0 -146
- package/coverage/lcov-report/prettify.css +0 -1
- package/coverage/lcov-report/prettify.js +0 -2
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -210
- package/coverage/lcov-report/src/bootstrap.js.html +0 -346
- package/coverage/lcov-report/src/config/index.html +0 -116
- package/coverage/lcov-report/src/config/index.js.html +0 -106
- package/coverage/lcov-report/src/constants.js.html +0 -850
- package/coverage/lcov-report/src/content-types/audit-log/index.html +0 -116
- package/coverage/lcov-report/src/content-types/audit-log/index.js.html +0 -94
- package/coverage/lcov-report/src/content-types/index.html +0 -116
- package/coverage/lcov-report/src/content-types/index.js.html +0 -112
- package/coverage/lcov-report/src/content-types/realm-admin/index.html +0 -116
- package/coverage/lcov-report/src/content-types/realm-admin/index.js.html +0 -94
- package/coverage/lcov-report/src/content-types/realm-config/index.html +0 -116
- package/coverage/lcov-report/src/content-types/realm-config/index.js.html +0 -94
- package/coverage/lcov-report/src/controllers/audit.js.html +0 -517
- package/coverage/lcov-report/src/controllers/index.html +0 -161
- package/coverage/lcov-report/src/controllers/index.js.html +0 -112
- package/coverage/lcov-report/src/controllers/realm.js.html +0 -1057
- package/coverage/lcov-report/src/controllers/user.js.html +0 -1324
- package/coverage/lcov-report/src/destroy.js.html +0 -100
- package/coverage/lcov-report/src/index.html +0 -116
- package/coverage/lcov-report/src/policies/can-access-realm.js.html +0 -163
- package/coverage/lcov-report/src/policies/index.html +0 -146
- package/coverage/lcov-report/src/policies/index.js.html +0 -106
- package/coverage/lcov-report/src/policies/is-authenticated.js.html +0 -100
- package/coverage/lcov-report/src/register.js.html +0 -106
- package/coverage/lcov-report/src/routes/admin.js.html +0 -844
- package/coverage/lcov-report/src/routes/index.html +0 -131
- package/coverage/lcov-report/src/routes/index.js.html +0 -109
- package/coverage/lcov-report/src/services/audit-log.js.html +0 -673
- package/coverage/lcov-report/src/services/index.html +0 -176
- package/coverage/lcov-report/src/services/index.js.html +0 -124
- package/coverage/lcov-report/src/services/keycloak-client.js.html +0 -2359
- package/coverage/lcov-report/src/services/permission.js.html +0 -955
- package/coverage/lcov-report/src/services/realm.js.html +0 -1207
- package/coverage/lcov-report/src/services/user.js.html +0 -1924
- package/coverage/lcov-report/src/utils/errors.js.html +0 -274
- package/coverage/lcov-report/src/utils/index.html +0 -116
- package/coverage/lcov-report/src/utils/index.js.html +0 -103
- package/coverage/lcov.info +0 -804
- package/jest.config.cjs +0 -50
- package/server/src/bootstrap.js +0 -87
- package/server/src/config/index.js +0 -7
- package/server/src/constants.js +0 -255
- package/server/src/content-types/audit-log/index.js +0 -3
- package/server/src/content-types/audit-log/schema.json +0 -61
- package/server/src/content-types/index.js +0 -9
- package/server/src/content-types/realm-admin/index.js +0 -3
- package/server/src/content-types/realm-admin/schema.json +0 -45
- package/server/src/content-types/realm-config/index.js +0 -3
- package/server/src/content-types/realm-config/schema.json +0 -56
- package/server/src/controllers/audit.js +0 -144
- package/server/src/controllers/index.js +0 -9
- package/server/src/controllers/realm.js +0 -324
- package/server/src/controllers/user.js +0 -413
- package/server/src/destroy.js +0 -5
- package/server/src/index.js +0 -21
- package/server/src/policies/can-access-realm.js +0 -26
- package/server/src/policies/index.js +0 -7
- package/server/src/policies/is-authenticated.js +0 -5
- package/server/src/register.js +0 -7
- package/server/src/routes/admin.js +0 -253
- package/server/src/routes/index.js +0 -8
- package/server/src/services/audit-log.js +0 -196
- package/server/src/services/index.js +0 -13
- package/server/src/services/keycloak-client.js +0 -758
- package/server/src/services/permission.js +0 -290
- package/server/src/services/realm.js +0 -374
- package/server/src/services/user.js +0 -613
- package/server/src/utils/errors.js +0 -63
- package/server/src/utils/index.js +0 -6
package/README.md
CHANGED
|
@@ -1,81 +1,111 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="https://raw.githubusercontent.com/strapi/strapi/main/packages/core/admin/admin/src/assets/images/logo-strapi-2022.svg" width="
|
|
3
|
-
<
|
|
4
|
-
<img src="https://www.keycloak.org/resources/images/logo.svg" width="
|
|
2
|
+
<img src="https://raw.githubusercontent.com/strapi/strapi/main/packages/core/admin/admin/src/assets/images/logo-strapi-2022.svg" width="160" alt="Strapi Logo" />
|
|
3
|
+
<img src="https://user-images.githubusercontent.com/4129325/166460470-2e9d9f5c-3b8c-4fee-9754-1b1c90119e60.png" width="60" alt="handshake" />
|
|
4
|
+
<img src="https://www.keycloak.org/resources/images/logo.svg" width="160" alt="Keycloak Logo" />
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
|
-
<h1 align="center"
|
|
7
|
+
<h1 align="center">🏰 Strapi Plugin: Keycloak Realm Users</h1>
|
|
8
8
|
|
|
9
9
|
<p align="center">
|
|
10
|
-
<
|
|
10
|
+
<em>Manage Keycloak users across <strong>all your realms</strong> — without ever leaving Strapi.</em>
|
|
11
11
|
</p>
|
|
12
12
|
|
|
13
13
|
<p align="center">
|
|
14
|
-
<a href="
|
|
15
|
-
<
|
|
16
|
-
<
|
|
17
|
-
<
|
|
18
|
-
<a href="#api-reference">API</a> •
|
|
19
|
-
<a href="#permissions">Permissions</a> •
|
|
20
|
-
<a href="#contributing">Contributing</a>
|
|
14
|
+
<a href="https://www.npmjs.com/package/strapi-plugin-keycloak-realm-users"><img src="https://img.shields.io/npm/v/strapi-plugin-keycloak-realm-users?style=for-the-badge&logo=npm&logoColor=white&color=CB3837" alt="npm version" /></a>
|
|
15
|
+
<img src="https://img.shields.io/badge/Strapi-v5-4945FF?style=for-the-badge&logo=strapi&logoColor=white" alt="Strapi v5" />
|
|
16
|
+
<img src="https://img.shields.io/badge/Keycloak-17%2B-4D8AB5?style=for-the-badge&logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZmlsbD0id2hpdGUiIGQ9Ik0xMiAyTDIgN3Y1YzAgNS41NSAzLjg0IDEwLjc0IDEwIDEyIDYuMTYtMS4yNiAxMC02LjQ1IDEwLTEyVjdsLTEwLTV6Ii8+PC9zdmc+" alt="Keycloak 17+" />
|
|
17
|
+
<img src="https://img.shields.io/npm/l/strapi-plugin-keycloak-realm-users?style=for-the-badge&color=22C55E" alt="MIT License" />
|
|
21
18
|
</p>
|
|
22
19
|
|
|
23
20
|
<p align="center">
|
|
24
|
-
<
|
|
25
|
-
<
|
|
26
|
-
<
|
|
27
|
-
<
|
|
21
|
+
<a href="#-quick-start">Quick Start</a> •
|
|
22
|
+
<a href="#-what-can-it-do">Features</a> •
|
|
23
|
+
<a href="#%EF%B8%8F-configuration">Configuration</a> •
|
|
24
|
+
<a href="#-api-reference">API</a> •
|
|
25
|
+
<a href="#-troubleshooting">Troubleshooting</a>
|
|
28
26
|
</p>
|
|
29
27
|
|
|
30
28
|
---
|
|
31
29
|
|
|
32
|
-
##
|
|
30
|
+
## 💡 The Problem
|
|
33
31
|
|
|
34
|
-
|
|
35
|
-
- Switching between different Keycloak admin consoles
|
|
36
|
-
- Granting full Keycloak admin access to team members
|
|
37
|
-
- No centralized audit trail of user management actions
|
|
32
|
+
You have **multiple Keycloak realms** — dev, staging, production, client tenants — and managing users means:
|
|
38
33
|
|
|
39
|
-
|
|
34
|
+
- 🔀 Juggling between different Keycloak admin consoles
|
|
35
|
+
- 🔓 Giving **full Keycloak admin access** to people who just need to reset a password
|
|
36
|
+
- 🕵️ No centralized log of who did what, where, and when
|
|
37
|
+
|
|
38
|
+
## ✅ The Solution
|
|
39
|
+
|
|
40
|
+
Install this plugin. Now your **Strapi admin panel** is the single pane of glass for Keycloak user management — with **per-realm permissions**, **audit logging**, and **zero Keycloak console access required** for your team.
|
|
40
41
|
|
|
41
42
|
---
|
|
42
43
|
|
|
43
|
-
##
|
|
44
|
+
## 🚀 Quick Start
|
|
45
|
+
|
|
46
|
+
**1. Install**
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npm install strapi-plugin-keycloak-realm-users
|
|
50
|
+
# or
|
|
51
|
+
yarn add strapi-plugin-keycloak-realm-users
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**2. Enable**
|
|
55
|
+
|
|
56
|
+
```javascript
|
|
57
|
+
// config/plugins.js
|
|
58
|
+
module.exports = {
|
|
59
|
+
'strapi-plugin-keycloak-realm-users': {
|
|
60
|
+
enabled: true,
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**3. Connect a realm** — go to **Settings → Keycloak Realm Users → Create Realm**, fill in your Keycloak URL, client ID & secret, hit **Test Connection**, and you're live. 🎉
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## 🎯 What Can It Do?
|
|
44
70
|
|
|
45
71
|
<table>
|
|
46
72
|
<tr>
|
|
47
|
-
<td width="50%">
|
|
73
|
+
<td width="50%" valign="top">
|
|
48
74
|
|
|
49
75
|
### 🏰 Multi-Realm Management
|
|
50
|
-
Connect
|
|
76
|
+
Connect **unlimited Keycloak realms** from a single Strapi interface. Each realm gets its own credentials, color tag, and admin team.
|
|
77
|
+
|
|
78
|
+
### 🔐 Granular Permissions
|
|
79
|
+
Assign Strapi admins to specific realms with fine-grained control:
|
|
51
80
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
81
|
+
| Permission | What it unlocks |
|
|
82
|
+
|:---:|---|
|
|
83
|
+
| 👁️ **Read** | View users |
|
|
84
|
+
| ➕ **Create** | Add new users |
|
|
85
|
+
| ✏️ **Update** | Edit details, enable/disable |
|
|
86
|
+
| 🗑️ **Delete** | Remove users |
|
|
87
|
+
| 🔑 **Reset Password** | Change passwords (separate for compliance!) |
|
|
88
|
+
| 🎭 **Manage Roles** | Assign/remove Keycloak roles |
|
|
60
89
|
|
|
61
90
|
</td>
|
|
62
|
-
<td width="50%">
|
|
63
|
-
|
|
64
|
-
### 📋
|
|
65
|
-
Every action is logged
|
|
66
|
-
- Who performed
|
|
67
|
-
- What
|
|
68
|
-
- When it happened
|
|
69
|
-
- Which realm was affected
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
-
|
|
75
|
-
-
|
|
76
|
-
-
|
|
77
|
-
-
|
|
78
|
-
-
|
|
91
|
+
<td width="50%" valign="top">
|
|
92
|
+
|
|
93
|
+
### 📋 Full Audit Trail
|
|
94
|
+
Every action is logged:
|
|
95
|
+
- **Who** performed it
|
|
96
|
+
- **What** changed
|
|
97
|
+
- **When** it happened
|
|
98
|
+
- **Which realm** was affected
|
|
99
|
+
|
|
100
|
+
Never wonder "who deleted that user?" again.
|
|
101
|
+
|
|
102
|
+
### 🧰 Full User Lifecycle
|
|
103
|
+
- ➕ Create, ✏️ update, 🗑️ delete users
|
|
104
|
+
- ✅ Enable / disable accounts
|
|
105
|
+
- 🔑 Reset passwords (temporary or permanent)
|
|
106
|
+
- 📧 Send verification & password reset emails
|
|
107
|
+
- 📦 Bulk import from JSON/CSV
|
|
108
|
+
- 📤 Export users
|
|
79
109
|
|
|
80
110
|
</td>
|
|
81
111
|
</tr>
|
|
@@ -83,403 +113,276 @@ Every action is logged with:
|
|
|
83
113
|
|
|
84
114
|
---
|
|
85
115
|
|
|
86
|
-
##
|
|
116
|
+
## 🏗️ How It Works
|
|
87
117
|
|
|
88
118
|
```
|
|
89
|
-
|
|
90
|
-
│
|
|
91
|
-
|
|
92
|
-
│
|
|
93
|
-
│ │
|
|
94
|
-
│ │
|
|
95
|
-
│
|
|
96
|
-
│
|
|
97
|
-
│
|
|
98
|
-
│
|
|
99
|
-
│
|
|
100
|
-
│
|
|
101
|
-
│
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
│ Realm A │ │ Realm B │ │ Realm C │
|
|
111
|
-
└────────────┘ └────────────┘ └────────────┘
|
|
119
|
+
┌──────────────────────────────────────────────────────────┐
|
|
120
|
+
│ Strapi Admin Panel │
|
|
121
|
+
│ │
|
|
122
|
+
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
|
123
|
+
│ │ Realms │ │ Users │ │ Audit │ │
|
|
124
|
+
│ │ Config │ │ Manager │ │ Log │ │
|
|
125
|
+
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
|
|
126
|
+
│ └───────────────┼──────────────┘ │
|
|
127
|
+
│ ▼ │
|
|
128
|
+
│ ┌───────────────────────────────┐ │
|
|
129
|
+
│ │ Permission Layer │ │
|
|
130
|
+
│ │ (per-realm access control) │ │
|
|
131
|
+
│ └───────────────┬───────────────┘ │
|
|
132
|
+
└────────────────────────┼─────────────────────────────────┘
|
|
133
|
+
│
|
|
134
|
+
┌──────────────┼──────────────┐
|
|
135
|
+
▼ ▼ ▼
|
|
136
|
+
┌────────────┐ ┌────────────┐ ┌────────────┐
|
|
137
|
+
│ Keycloak │ │ Keycloak │ │ Keycloak │
|
|
138
|
+
│ Realm A │ │ Realm B │ │ Realm C │
|
|
139
|
+
└────────────┘ └────────────┘ └────────────┘
|
|
112
140
|
```
|
|
113
141
|
|
|
142
|
+
Your Strapi admins **never touch Keycloak directly**. They get exactly the permissions they need, and every action is logged.
|
|
143
|
+
|
|
114
144
|
---
|
|
115
145
|
|
|
116
|
-
##
|
|
146
|
+
## ⚙️ Configuration
|
|
117
147
|
|
|
118
|
-
|
|
119
|
-
# Using npm
|
|
120
|
-
npm install strapi-plugin-keycloak-realm-users
|
|
148
|
+
### Keycloak Client Setup
|
|
121
149
|
|
|
122
|
-
|
|
123
|
-
yarn add strapi-plugin-keycloak-realm-users
|
|
124
|
-
```
|
|
150
|
+
For each realm you want to manage, create a **service account client** in Keycloak:
|
|
125
151
|
|
|
126
|
-
|
|
152
|
+
<details>
|
|
153
|
+
<summary>📖 <strong>Step-by-step Keycloak setup</strong> (click to expand)</summary>
|
|
127
154
|
|
|
128
|
-
|
|
155
|
+
<br />
|
|
129
156
|
|
|
130
|
-
|
|
157
|
+
**1. Create a new client** in your Keycloak realm:
|
|
158
|
+
- Client ID: `strapi-admin` (or your preferred name)
|
|
159
|
+
- Client Protocol: `openid-connect`
|
|
131
160
|
|
|
132
|
-
|
|
133
|
-
// config/plugins.js
|
|
134
|
-
module.exports = {
|
|
135
|
-
'strapi-plugin-keycloak-realm-users': {
|
|
136
|
-
enabled: true,
|
|
137
|
-
},
|
|
138
|
-
};
|
|
139
|
-
```
|
|
161
|
+
**2. Configure client settings:**
|
|
140
162
|
|
|
141
|
-
|
|
163
|
+
| Setting | Value |
|
|
164
|
+
|---------|-------|
|
|
165
|
+
| Client authentication | **ON** |
|
|
166
|
+
| Service accounts roles | **Enabled** |
|
|
142
167
|
|
|
143
|
-
|
|
168
|
+
**3. Assign service account roles:**
|
|
144
169
|
|
|
145
|
-
|
|
146
|
-
<summary><strong>Keycloak Client Setup (Click to expand)</strong></summary>
|
|
147
|
-
|
|
148
|
-
1. **Create a new client** in your Keycloak realm:
|
|
149
|
-
- Client ID: `strapi-admin` (or your preferred name)
|
|
150
|
-
- Client Protocol: `openid-connect`
|
|
151
|
-
|
|
152
|
-
2. **Configure client settings**:
|
|
153
|
-
| Setting | Value |
|
|
154
|
-
|---------|-------|
|
|
155
|
-
| Client authentication | ON |
|
|
156
|
-
| Service accounts roles | Enabled |
|
|
157
|
-
| Valid redirect URIs | (not required for service accounts) |
|
|
158
|
-
|
|
159
|
-
3. **Assign Service Account Roles**:
|
|
160
|
-
- Go to the client's **Service Account Roles** tab
|
|
161
|
-
- Click **Assign role**
|
|
162
|
-
- Filter by **realm-management** client
|
|
163
|
-
- Assign the following roles:
|
|
164
|
-
|
|
165
|
-
| Role | Required For |
|
|
166
|
-
|------|--------------|
|
|
167
|
-
| `view-users` | Listing and viewing users |
|
|
168
|
-
| `manage-users` | Creating, updating, deleting users |
|
|
169
|
-
| `view-realm` | Testing connection |
|
|
170
|
-
| `query-users` | Searching users |
|
|
171
|
-
|
|
172
|
-
> **Tip**: For full admin access, you can assign `realm-admin` instead.
|
|
173
|
-
|
|
174
|
-
4. **Get the client secret**:
|
|
175
|
-
- Go to the **Credentials** tab
|
|
176
|
-
- Copy the **Client secret**
|
|
170
|
+
Go to **Service Account Roles** → **Assign role** → Filter by **realm-management** → Add:
|
|
177
171
|
|
|
178
|
-
|
|
172
|
+
| Role | Why |
|
|
173
|
+
|:---:|---|
|
|
174
|
+
| `view-users` | List & view users |
|
|
175
|
+
| `manage-users` | Create, update, delete users |
|
|
176
|
+
| `view-realm` | Test connection |
|
|
177
|
+
| `query-users` | Search users |
|
|
179
178
|
|
|
180
|
-
|
|
179
|
+
> 💡 **Shortcut**: Assign `realm-admin` for full access.
|
|
181
180
|
|
|
182
|
-
|
|
181
|
+
**4. Copy the client secret** from the **Credentials** tab.
|
|
183
182
|
|
|
184
|
-
|
|
183
|
+
</details>
|
|
185
184
|
|
|
186
|
-
|
|
187
|
-
2. Click **Create Realm**
|
|
188
|
-
3. Fill in the connection details:
|
|
185
|
+
### Adding a Realm in Strapi
|
|
189
186
|
|
|
190
|
-
| Field |
|
|
191
|
-
|
|
192
|
-
| Name | Unique
|
|
193
|
-
| Display Name | Human-readable
|
|
194
|
-
| Server URL | Keycloak base URL | `https://keycloak.example.com` |
|
|
195
|
-
| Realm Name |
|
|
196
|
-
| Client ID | Service account client
|
|
197
|
-
| Client Secret |
|
|
198
|
-
| Color | UI accent color | `#4945ff` |
|
|
187
|
+
| Field | What it is | Example |
|
|
188
|
+
|-------|-----------|---------|
|
|
189
|
+
| **Name** | Unique slug (lowercase, hyphens) | `production-users` |
|
|
190
|
+
| **Display Name** | Human-readable label | `Production Users` |
|
|
191
|
+
| **Server URL** | Keycloak base URL | `https://keycloak.example.com` |
|
|
192
|
+
| **Realm Name** | Keycloak realm | `my-realm` |
|
|
193
|
+
| **Client ID** | Service account client | `strapi-admin` |
|
|
194
|
+
| **Client Secret** | From credentials tab | `xxxxx-xxxxx-xxxxx` |
|
|
195
|
+
| **Color** | UI accent color | `#4945ff` |
|
|
199
196
|
|
|
200
|
-
|
|
201
|
-
5. Click **Save**
|
|
197
|
+
Hit **Test Connection** → **Save** → Done! ✅
|
|
202
198
|
|
|
203
|
-
|
|
199
|
+
---
|
|
204
200
|
|
|
205
|
-
|
|
201
|
+
## 👥 Managing Users
|
|
206
202
|
|
|
207
|
-
|
|
208
|
-
- **Search**: Use the search bar to filter by username, email, or name
|
|
209
|
-
- **Create**: Click "Create User" and fill in the details
|
|
210
|
-
- **Edit**: Click the edit icon to modify user details
|
|
211
|
-
- **Actions**:
|
|
212
|
-
- 🔑 Reset password
|
|
213
|
-
- ✅ Enable/disable account
|
|
214
|
-
- 📧 Send verification email
|
|
215
|
-
- 🗑️ Delete user
|
|
203
|
+
Once a realm is connected:
|
|
216
204
|
|
|
217
|
-
|
|
205
|
+
| Action | How |
|
|
206
|
+
|--------|-----|
|
|
207
|
+
| **Browse users** | Click "Manage Users" on any realm card |
|
|
208
|
+
| **Search** | Filter by username, email, or name |
|
|
209
|
+
| **Create user** | Click "Create User" → fill in details |
|
|
210
|
+
| **Edit user** | Click the edit icon on any row |
|
|
211
|
+
| **Reset password** | 🔑 Set temporary or permanent password |
|
|
212
|
+
| **Toggle account** | ✅ Enable or disable with one click |
|
|
213
|
+
| **Verification email** | 📧 Send from the user actions menu |
|
|
214
|
+
| **Delete user** | 🗑️ With confirmation dialog |
|
|
215
|
+
| **Bulk import** | 📦 Upload JSON or CSV |
|
|
216
|
+
| **Export** | 📤 Download all realm users |
|
|
218
217
|
|
|
219
|
-
|
|
218
|
+
### Assigning Realm Admins
|
|
220
219
|
|
|
221
|
-
|
|
222
|
-
2. Go to the **Admins** tab
|
|
223
|
-
3. Click **Add Admin**
|
|
224
|
-
4. Select a Strapi user
|
|
225
|
-
5. Configure their permissions:
|
|
220
|
+
Super admins can delegate realm management to other Strapi users:
|
|
226
221
|
|
|
227
222
|
```
|
|
228
|
-
|
|
229
|
-
│ Admin: john@example.com
|
|
230
|
-
|
|
231
|
-
│ ☑ Can Read
|
|
232
|
-
│ ☑ Can Update
|
|
233
|
-
│ ☐ Can Manage Roles
|
|
234
|
-
|
|
223
|
+
┌─────────────────────────────────────────────────────────┐
|
|
224
|
+
│ Admin: john@example.com │
|
|
225
|
+
├─────────────────────────────────────────────────────────┤
|
|
226
|
+
│ ☑ Can Read ☑ Can Create ☐ Can Delete │
|
|
227
|
+
│ ☑ Can Update ☐ Can Reset Password │
|
|
228
|
+
│ ☐ Can Manage Roles │
|
|
229
|
+
└─────────────────────────────────────────────────────────┘
|
|
235
230
|
```
|
|
236
231
|
|
|
232
|
+
Each admin sees **only the realms they're assigned to** with **only the actions they're permitted**.
|
|
233
|
+
|
|
237
234
|
---
|
|
238
235
|
|
|
239
|
-
## API Reference
|
|
236
|
+
## 📡 API Reference
|
|
240
237
|
|
|
241
|
-
|
|
238
|
+
All endpoints live under `/api/keycloak-realm-users`.
|
|
242
239
|
|
|
243
240
|
### Realms
|
|
244
241
|
|
|
245
242
|
| Method | Endpoint | Description |
|
|
246
|
-
|
|
247
|
-
| `GET` | `/
|
|
248
|
-
| `GET` | `/
|
|
249
|
-
| `POST` | `/
|
|
250
|
-
| `PUT` | `/
|
|
251
|
-
| `DELETE` | `/
|
|
252
|
-
| `POST` | `/
|
|
243
|
+
|:------:|----------|-------------|
|
|
244
|
+
| `GET` | `/realms` | List all accessible realms |
|
|
245
|
+
| `GET` | `/realms/:id` | Get realm details |
|
|
246
|
+
| `POST` | `/realms` | Create realm *(super admin)* |
|
|
247
|
+
| `PUT` | `/realms/:id` | Update realm *(super admin)* |
|
|
248
|
+
| `DELETE` | `/realms/:id` | Delete realm *(super admin)* |
|
|
249
|
+
| `POST` | `/realms/:id/test` | Test connection |
|
|
253
250
|
|
|
254
251
|
### Users
|
|
255
252
|
|
|
256
253
|
| Method | Endpoint | Description |
|
|
257
|
-
|
|
258
|
-
| `GET` | `/
|
|
259
|
-
| `GET` | `/
|
|
260
|
-
| `POST` | `/
|
|
261
|
-
| `PUT` | `/
|
|
262
|
-
| `DELETE` | `/
|
|
254
|
+
|:------:|----------|-------------|
|
|
255
|
+
| `GET` | `/realms/:id/users` | List users (paginated) |
|
|
256
|
+
| `GET` | `/realms/:id/users/:userId` | Get user details |
|
|
257
|
+
| `POST` | `/realms/:id/users` | Create user |
|
|
258
|
+
| `PUT` | `/realms/:id/users/:userId` | Update user |
|
|
259
|
+
| `DELETE` | `/realms/:id/users/:userId` | Delete user |
|
|
263
260
|
|
|
264
261
|
### User Actions
|
|
265
262
|
|
|
266
263
|
| Method | Endpoint | Description |
|
|
267
|
-
|
|
268
|
-
| `POST` |
|
|
269
|
-
| `POST` |
|
|
270
|
-
| `POST` |
|
|
271
|
-
| `POST` |
|
|
272
|
-
| `POST` |
|
|
264
|
+
|:------:|----------|-------------|
|
|
265
|
+
| `POST` | `/.../users/:userId/reset-password` | Reset password |
|
|
266
|
+
| `POST` | `/.../users/:userId/enable` | Enable user |
|
|
267
|
+
| `POST` | `/.../users/:userId/disable` | Disable user |
|
|
268
|
+
| `POST` | `/.../users/:userId/send-verify-email` | Send verification email |
|
|
269
|
+
| `POST` | `/.../users/:userId/send-reset-password-email` | Send password reset email |
|
|
273
270
|
|
|
274
271
|
### Roles
|
|
275
272
|
|
|
276
273
|
| Method | Endpoint | Description |
|
|
277
|
-
|
|
278
|
-
| `GET` |
|
|
279
|
-
| `GET` |
|
|
280
|
-
| `POST` |
|
|
281
|
-
| `DELETE` |
|
|
274
|
+
|:------:|----------|-------------|
|
|
275
|
+
| `GET` | `/.../realms/:id/roles` | List realm roles |
|
|
276
|
+
| `GET` | `/.../users/:userId/roles` | Get user's roles |
|
|
277
|
+
| `POST` | `/.../users/:userId/roles` | Assign roles |
|
|
278
|
+
| `DELETE` | `/.../users/:userId/roles` | Remove roles |
|
|
282
279
|
|
|
283
|
-
### Bulk Operations
|
|
280
|
+
### Bulk Operations & Audit
|
|
284
281
|
|
|
285
282
|
| Method | Endpoint | Description |
|
|
286
|
-
|
|
287
|
-
| `POST` |
|
|
288
|
-
| `GET` |
|
|
289
|
-
|
|
290
|
-
### Audit Log
|
|
291
|
-
|
|
292
|
-
| Method | Endpoint | Description |
|
|
293
|
-
|--------|----------|-------------|
|
|
294
|
-
| `GET` | `/api/keycloak-realm-users/audit` | Query audit logs |
|
|
283
|
+
|:------:|----------|-------------|
|
|
284
|
+
| `POST` | `/.../realms/:id/users/import` | Bulk import users |
|
|
285
|
+
| `GET` | `/.../realms/:id/users/export` | Export all users |
|
|
286
|
+
| `GET` | `/audit` | Query audit logs |
|
|
295
287
|
|
|
296
288
|
---
|
|
297
289
|
|
|
298
|
-
##
|
|
299
|
-
|
|
300
|
-
### Permission Hierarchy
|
|
301
|
-
|
|
302
|
-
```
|
|
303
|
-
Super Admin (Strapi)
|
|
304
|
-
│
|
|
305
|
-
├── Can manage all realms
|
|
306
|
-
├── Can create/edit/delete realm configurations
|
|
307
|
-
└── Can assign realm admins
|
|
308
|
-
│
|
|
309
|
-
└── Realm Admin (Assigned per realm)
|
|
310
|
-
│
|
|
311
|
-
├── canRead → View users
|
|
312
|
-
├── canCreate → Create users
|
|
313
|
-
├── canUpdate → Update user details, enable/disable
|
|
314
|
-
├── canDelete → Delete users
|
|
315
|
-
├── canResetPassword → Reset passwords, send password reset emails
|
|
316
|
-
└── canManageRoles → Assign/remove Keycloak roles
|
|
317
|
-
```
|
|
318
|
-
|
|
319
|
-
### RBAC Integration
|
|
290
|
+
## 🛡️ Security
|
|
320
291
|
|
|
321
|
-
|
|
292
|
+
| Aspect | How we handle it |
|
|
293
|
+
|--------|-----------------|
|
|
294
|
+
| 🔒 **Client Secrets** | Stored with `private: true` — never exposed in API responses |
|
|
295
|
+
| ⚡ **Token Caching** | Access tokens cached in memory, auto-refreshed before expiry |
|
|
296
|
+
| 🚪 **Permission Checks** | Every API call validated before execution |
|
|
297
|
+
| 📋 **Audit Trail** | All actions logged with performer identity |
|
|
298
|
+
| ✅ **Input Validation** | Server-side validation on all inputs |
|
|
299
|
+
| 🧹 **Error Sanitization** | Internal details never leak to clients |
|
|
322
300
|
|
|
323
301
|
---
|
|
324
302
|
|
|
325
|
-
##
|
|
326
|
-
|
|
327
|
-
### Realm Configuration
|
|
328
|
-
|
|
329
|
-
```typescript
|
|
330
|
-
interface RealmConfig {
|
|
331
|
-
name: string; // Unique slug identifier
|
|
332
|
-
displayName: string; // Human-readable name
|
|
333
|
-
serverUrl: string; // Keycloak server URL
|
|
334
|
-
realmName: string; // Keycloak realm name
|
|
335
|
-
clientId: string; // Service account client ID
|
|
336
|
-
clientSecret: string; // Client secret (stored securely)
|
|
337
|
-
enabled: boolean; // Whether realm is active
|
|
338
|
-
color: string; // UI accent color
|
|
339
|
-
}
|
|
340
|
-
```
|
|
341
|
-
|
|
342
|
-
### Audit Log Entry
|
|
343
|
-
|
|
344
|
-
```typescript
|
|
345
|
-
interface AuditLog {
|
|
346
|
-
action: 'CREATE_USER' | 'UPDATE_USER' | 'DELETE_USER' |
|
|
347
|
-
'RESET_PASSWORD' | 'ENABLE_USER' | 'DISABLE_USER' |
|
|
348
|
-
'ASSIGN_ROLE' | 'REMOVE_ROLE' | 'BULK_IMPORT' | ...;
|
|
349
|
-
realmName: string;
|
|
350
|
-
realmDisplayName: string;
|
|
351
|
-
keycloakUserId: string;
|
|
352
|
-
keycloakUsername: string;
|
|
353
|
-
performedBy: number; // Strapi admin user ID
|
|
354
|
-
performedByEmail: string;
|
|
355
|
-
details: object; // Action-specific metadata
|
|
356
|
-
createdAt: Date;
|
|
357
|
-
}
|
|
358
|
-
```
|
|
359
|
-
|
|
360
|
-
---
|
|
361
|
-
|
|
362
|
-
## Security Considerations
|
|
363
|
-
|
|
364
|
-
| Aspect | Implementation |
|
|
365
|
-
|--------|----------------|
|
|
366
|
-
| **Client Secrets** | Stored with `private: true` attribute, never exposed in API responses |
|
|
367
|
-
| **Token Caching** | Access tokens cached in memory with automatic refresh before expiry |
|
|
368
|
-
| **Permission Checks** | Every API call validates user permissions before execution |
|
|
369
|
-
| **Audit Trail** | All user management actions logged with performer identity |
|
|
370
|
-
| **Input Validation** | Server-side validation on all inputs |
|
|
371
|
-
| **Error Sanitization** | Internal errors sanitized before sending to client |
|
|
372
|
-
|
|
373
|
-
---
|
|
374
|
-
|
|
375
|
-
## Troubleshooting
|
|
303
|
+
## 🔧 Troubleshooting
|
|
376
304
|
|
|
377
305
|
<details>
|
|
378
|
-
<summary
|
|
306
|
+
<summary>🔴 <strong>403 Forbidden when testing connection</strong></summary>
|
|
379
307
|
|
|
380
|
-
|
|
308
|
+
The Keycloak client is missing required roles.
|
|
381
309
|
|
|
382
|
-
**
|
|
310
|
+
**Fix**: Keycloak → Your Client → Service Account Roles → Assign from `realm-management`:
|
|
383
311
|
- `view-realm`
|
|
384
312
|
- `view-users`
|
|
385
313
|
- `manage-users`
|
|
386
314
|
- `query-users`
|
|
387
|
-
|
|
388
315
|
</details>
|
|
389
316
|
|
|
390
317
|
<details>
|
|
391
|
-
<summary
|
|
392
|
-
|
|
393
|
-
The client secret may have changed or been entered incorrectly.
|
|
318
|
+
<summary>🔴 <strong>Invalid client secret</strong></summary>
|
|
394
319
|
|
|
395
|
-
|
|
396
|
-
1. Go to Keycloak → Your Client → Credentials tab
|
|
397
|
-
2. Regenerate or copy the current secret
|
|
398
|
-
3. Update the realm configuration in Strapi
|
|
320
|
+
The secret may have changed or was entered incorrectly.
|
|
399
321
|
|
|
322
|
+
**Fix**: Keycloak → Your Client → Credentials tab → Copy the current secret → Update in Strapi.
|
|
400
323
|
</details>
|
|
401
324
|
|
|
402
325
|
<details>
|
|
403
|
-
<summary
|
|
326
|
+
<summary>🔴 <strong>Connection works but users fail to load</strong></summary>
|
|
404
327
|
|
|
405
|
-
Test connection only
|
|
406
|
-
|
|
407
|
-
**Solution**: Ensure your client has `view-users` and `query-users` roles from `realm-management`.
|
|
328
|
+
Test connection only checks basic realm access. User operations need extra permissions.
|
|
408
329
|
|
|
330
|
+
**Fix**: Ensure your client has `view-users` and `query-users` roles from `realm-management`.
|
|
409
331
|
</details>
|
|
410
332
|
|
|
411
333
|
---
|
|
412
334
|
|
|
413
|
-
## Compatibility
|
|
335
|
+
## 📦 Compatibility
|
|
414
336
|
|
|
415
|
-
|
|
|
416
|
-
|
|
417
|
-
|
|
|
337
|
+
| | Version |
|
|
338
|
+
|---|---------|
|
|
339
|
+
| **Strapi** | v5.x |
|
|
340
|
+
| **Keycloak** | 17+ *(recommended: 22+)* |
|
|
341
|
+
| **Node.js** | 18+ |
|
|
418
342
|
|
|
419
|
-
>
|
|
343
|
+
> ⚠️ Keycloak versions below 17 use the legacy `/auth/...` URL prefix, which this plugin does not support.
|
|
420
344
|
|
|
421
345
|
---
|
|
422
346
|
|
|
423
|
-
## Development
|
|
424
|
-
|
|
425
|
-
### Setup
|
|
347
|
+
## 🧪 Development
|
|
426
348
|
|
|
427
349
|
```bash
|
|
428
|
-
# Clone the repository
|
|
429
|
-
git clone https://github.com/your-org/strapi-plugin-keycloak-realm-users
|
|
430
|
-
|
|
431
350
|
# Install dependencies
|
|
432
351
|
npm install
|
|
433
|
-
```
|
|
434
|
-
|
|
435
|
-
### Testing
|
|
436
352
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
```bash
|
|
440
|
-
# Run all tests
|
|
353
|
+
# Run tests
|
|
441
354
|
npm test
|
|
442
355
|
|
|
443
|
-
#
|
|
356
|
+
# Watch mode
|
|
444
357
|
npm run test:watch
|
|
445
358
|
|
|
446
|
-
#
|
|
359
|
+
# Coverage report
|
|
447
360
|
npm run test:coverage
|
|
448
361
|
```
|
|
449
362
|
|
|
450
|
-
**Coverage thresholds
|
|
451
|
-
- Branches: 75%
|
|
452
|
-
- Functions: 95%
|
|
453
|
-
- Lines: 90%
|
|
454
|
-
- Statements: 90%
|
|
455
|
-
|
|
456
|
-
### Code Standards
|
|
457
|
-
|
|
458
|
-
- **Pure ES6+** - Modern JavaScript throughout
|
|
459
|
-
- **JSDoc Documentation** - All public functions, hooks, and types are fully documented
|
|
460
|
-
- **Error Handling** - Sanitized errors prevent internal details from leaking to clients
|
|
461
|
-
- **Centralized Constants** - No magic values; all constants defined in dedicated modules
|
|
363
|
+
**Coverage thresholds**: Branches 75% · Functions 95% · Lines 90% · Statements 90%
|
|
462
364
|
|
|
463
365
|
---
|
|
464
366
|
|
|
465
|
-
## Contributing
|
|
367
|
+
## 🤝 Contributing
|
|
466
368
|
|
|
467
|
-
Contributions
|
|
369
|
+
Contributions welcome! Before submitting a PR:
|
|
468
370
|
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
4. Follow the existing code style and patterns
|
|
371
|
+
1. ✅ All tests pass: `npm test`
|
|
372
|
+
2. 📊 Coverage maintained: `npm run test:coverage`
|
|
373
|
+
3. 📝 JSDoc added for new public APIs
|
|
374
|
+
4. 🎨 Follows existing code style
|
|
474
375
|
|
|
475
376
|
---
|
|
476
377
|
|
|
477
|
-
## License
|
|
378
|
+
## 📄 License
|
|
478
379
|
|
|
479
|
-
MIT
|
|
380
|
+
[MIT](LICENSE) — use it, fork it, ship it.
|
|
480
381
|
|
|
481
382
|
---
|
|
482
383
|
|
|
483
384
|
<p align="center">
|
|
484
|
-
<sub>Built with ❤️ for the Strapi
|
|
385
|
+
<sub>Built with ❤️ for the Strapi community</sub>
|
|
386
|
+
<br />
|
|
387
|
+
<sub>If this plugin saved you time, give it a ⭐ on GitHub!</sub>
|
|
485
388
|
</p>
|