strapi-plugin-keycloak-realm-users 1.0.0

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.
Files changed (123) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +485 -0
  3. package/__tests__/constants.test.mjs +207 -0
  4. package/__tests__/mocks/strapi.mjs +182 -0
  5. package/__tests__/services/audit-log.test.mjs +283 -0
  6. package/__tests__/services/keycloak-client.test.mjs +651 -0
  7. package/__tests__/services/permission.test.mjs +374 -0
  8. package/__tests__/services/realm.test.mjs +415 -0
  9. package/__tests__/services/user.test.mjs +487 -0
  10. package/__tests__/utils/errors.test.mjs +109 -0
  11. package/admin/src/components/Initializer.jsx +14 -0
  12. package/admin/src/components/RealmBadge.jsx +17 -0
  13. package/admin/src/constants.js +14 -0
  14. package/admin/src/hooks/useAuditLogs.js +142 -0
  15. package/admin/src/hooks/useKeycloakRoles.js +182 -0
  16. package/admin/src/hooks/useKeycloakUsers.js +477 -0
  17. package/admin/src/hooks/useRealmAdmins.js +249 -0
  18. package/admin/src/hooks/useRealms.js +269 -0
  19. package/admin/src/index.js +46 -0
  20. package/admin/src/pages/App.jsx +21 -0
  21. package/admin/src/pages/AuditPage/index.jsx +213 -0
  22. package/admin/src/pages/RealmsPage/RealmEditPage.jsx +791 -0
  23. package/admin/src/pages/RealmsPage/RealmListPage.jsx +231 -0
  24. package/admin/src/pages/RealmsPage/index.jsx +7 -0
  25. package/admin/src/pages/UsersPage/UserEditPage.jsx +313 -0
  26. package/admin/src/pages/UsersPage/UserListPage.jsx +437 -0
  27. package/admin/src/pages/UsersPage/index.jsx +7 -0
  28. package/admin/src/pluginId.js +2 -0
  29. package/admin/src/translations/en.json +77 -0
  30. package/admin/src/translations/fr.json +77 -0
  31. package/babel.config.cjs +17 -0
  32. package/coverage/clover.xml +422 -0
  33. package/coverage/coverage-final.json +8 -0
  34. package/coverage/lcov-report/base.css +224 -0
  35. package/coverage/lcov-report/block-navigation.js +87 -0
  36. package/coverage/lcov-report/favicon.png +0 -0
  37. package/coverage/lcov-report/index.html +146 -0
  38. package/coverage/lcov-report/prettify.css +1 -0
  39. package/coverage/lcov-report/prettify.js +2 -0
  40. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  41. package/coverage/lcov-report/sorter.js +210 -0
  42. package/coverage/lcov-report/src/bootstrap.js.html +346 -0
  43. package/coverage/lcov-report/src/config/index.html +116 -0
  44. package/coverage/lcov-report/src/config/index.js.html +106 -0
  45. package/coverage/lcov-report/src/constants.js.html +850 -0
  46. package/coverage/lcov-report/src/content-types/audit-log/index.html +116 -0
  47. package/coverage/lcov-report/src/content-types/audit-log/index.js.html +94 -0
  48. package/coverage/lcov-report/src/content-types/index.html +116 -0
  49. package/coverage/lcov-report/src/content-types/index.js.html +112 -0
  50. package/coverage/lcov-report/src/content-types/realm-admin/index.html +116 -0
  51. package/coverage/lcov-report/src/content-types/realm-admin/index.js.html +94 -0
  52. package/coverage/lcov-report/src/content-types/realm-config/index.html +116 -0
  53. package/coverage/lcov-report/src/content-types/realm-config/index.js.html +94 -0
  54. package/coverage/lcov-report/src/controllers/audit.js.html +517 -0
  55. package/coverage/lcov-report/src/controllers/index.html +161 -0
  56. package/coverage/lcov-report/src/controllers/index.js.html +112 -0
  57. package/coverage/lcov-report/src/controllers/realm.js.html +1057 -0
  58. package/coverage/lcov-report/src/controllers/user.js.html +1324 -0
  59. package/coverage/lcov-report/src/destroy.js.html +100 -0
  60. package/coverage/lcov-report/src/index.html +116 -0
  61. package/coverage/lcov-report/src/policies/can-access-realm.js.html +163 -0
  62. package/coverage/lcov-report/src/policies/index.html +146 -0
  63. package/coverage/lcov-report/src/policies/index.js.html +106 -0
  64. package/coverage/lcov-report/src/policies/is-authenticated.js.html +100 -0
  65. package/coverage/lcov-report/src/register.js.html +106 -0
  66. package/coverage/lcov-report/src/routes/admin.js.html +844 -0
  67. package/coverage/lcov-report/src/routes/index.html +131 -0
  68. package/coverage/lcov-report/src/routes/index.js.html +109 -0
  69. package/coverage/lcov-report/src/services/audit-log.js.html +673 -0
  70. package/coverage/lcov-report/src/services/index.html +176 -0
  71. package/coverage/lcov-report/src/services/index.js.html +124 -0
  72. package/coverage/lcov-report/src/services/keycloak-client.js.html +2359 -0
  73. package/coverage/lcov-report/src/services/permission.js.html +955 -0
  74. package/coverage/lcov-report/src/services/realm.js.html +1207 -0
  75. package/coverage/lcov-report/src/services/user.js.html +1924 -0
  76. package/coverage/lcov-report/src/utils/errors.js.html +274 -0
  77. package/coverage/lcov-report/src/utils/index.html +116 -0
  78. package/coverage/lcov-report/src/utils/index.js.html +103 -0
  79. package/coverage/lcov.info +804 -0
  80. package/dist/_chunks/App-BaKrvCeS.mjs +1975 -0
  81. package/dist/_chunks/App-DO6syS77.js +1975 -0
  82. package/dist/_chunks/en-Li-XBDe9.mjs +72 -0
  83. package/dist/_chunks/en-aCyfgNfr.js +72 -0
  84. package/dist/_chunks/fr-Cj33Q8jI.js +72 -0
  85. package/dist/_chunks/fr-vLrXph-Z.mjs +72 -0
  86. package/dist/_chunks/index-DwDO4-0C.js +69 -0
  87. package/dist/_chunks/index-jTVd7LdQ.mjs +70 -0
  88. package/dist/admin/index.js +3 -0
  89. package/dist/admin/index.mjs +4 -0
  90. package/dist/server/index.js +3003 -0
  91. package/dist/server/index.mjs +3004 -0
  92. package/jest.config.cjs +50 -0
  93. package/package.json +55 -0
  94. package/server/src/bootstrap.js +87 -0
  95. package/server/src/config/index.js +7 -0
  96. package/server/src/constants.js +255 -0
  97. package/server/src/content-types/audit-log/index.js +3 -0
  98. package/server/src/content-types/audit-log/schema.json +61 -0
  99. package/server/src/content-types/index.js +9 -0
  100. package/server/src/content-types/realm-admin/index.js +3 -0
  101. package/server/src/content-types/realm-admin/schema.json +45 -0
  102. package/server/src/content-types/realm-config/index.js +3 -0
  103. package/server/src/content-types/realm-config/schema.json +56 -0
  104. package/server/src/controllers/audit.js +144 -0
  105. package/server/src/controllers/index.js +9 -0
  106. package/server/src/controllers/realm.js +324 -0
  107. package/server/src/controllers/user.js +413 -0
  108. package/server/src/destroy.js +5 -0
  109. package/server/src/index.js +21 -0
  110. package/server/src/policies/can-access-realm.js +26 -0
  111. package/server/src/policies/index.js +7 -0
  112. package/server/src/policies/is-authenticated.js +5 -0
  113. package/server/src/register.js +7 -0
  114. package/server/src/routes/admin.js +253 -0
  115. package/server/src/routes/index.js +8 -0
  116. package/server/src/services/audit-log.js +196 -0
  117. package/server/src/services/index.js +13 -0
  118. package/server/src/services/keycloak-client.js +758 -0
  119. package/server/src/services/permission.js +290 -0
  120. package/server/src/services/realm.js +374 -0
  121. package/server/src/services/user.js +613 -0
  122. package/server/src/utils/errors.js +63 -0
  123. package/server/src/utils/index.js +6 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Sonatel
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,485 @@
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="200" alt="Strapi Logo" />
3
+ <span style="font-size: 48px; margin: 0 20px;">+</span>
4
+ <img src="https://www.keycloak.org/resources/images/logo.svg" width="200" alt="Keycloak Logo" />
5
+ </p>
6
+
7
+ <h1 align="center">Strapi Plugin: Keycloak Realm Users</h1>
8
+
9
+ <p align="center">
10
+ <strong>Seamlessly manage Keycloak users across multiple realms directly from your Strapi admin panel</strong>
11
+ </p>
12
+
13
+ <p align="center">
14
+ <a href="#features">Features</a> •
15
+ <a href="#installation">Installation</a> •
16
+ <a href="#configuration">Configuration</a> •
17
+ <a href="#usage">Usage</a> •
18
+ <a href="#api-reference">API</a> •
19
+ <a href="#permissions">Permissions</a> •
20
+ <a href="#contributing">Contributing</a>
21
+ </p>
22
+
23
+ <p align="center">
24
+ <img src="https://img.shields.io/npm/v/strapi-plugin-keycloak-realm-users?style=flat-square&color=4945ff" alt="npm version" />
25
+ <img src="https://img.shields.io/npm/l/strapi-plugin-keycloak-realm-users?style=flat-square" alt="license" />
26
+ <img src="https://img.shields.io/badge/strapi-v5-blue?style=flat-square" alt="Strapi v5" />
27
+ <img src="https://img.shields.io/badge/keycloak-17%2B-orange?style=flat-square" alt="Keycloak 17+" />
28
+ </p>
29
+
30
+ ---
31
+
32
+ ## Why This Plugin?
33
+
34
+ Managing users across multiple Keycloak realms typically requires:
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
38
+
39
+ **This plugin solves all of that** by bringing Keycloak user management into Strapi with fine-grained permissions, multi-realm support, and comprehensive audit logging.
40
+
41
+ ---
42
+
43
+ ## Features
44
+
45
+ <table>
46
+ <tr>
47
+ <td width="50%">
48
+
49
+ ### 🏰 Multi-Realm Management
50
+ Connect and manage users across unlimited Keycloak realms from a single interface. Each realm is configured independently with its own credentials.
51
+
52
+ ### 🔐 Fine-Grained Permissions
53
+ Assign Strapi admins to specific realms with granular permissions:
54
+ - **Read** - View users
55
+ - **Create** - Add new users
56
+ - **Update** - Modify user details, enable/disable accounts
57
+ - **Delete** - Remove users
58
+ - **Reset Password** - Change passwords (separate from Update for compliance)
59
+ - **Manage Roles** - Assign/remove Keycloak roles
60
+
61
+ </td>
62
+ <td width="50%">
63
+
64
+ ### 📋 Comprehensive Audit Log
65
+ Every action is logged with:
66
+ - Who performed the action
67
+ - What was changed
68
+ - When it happened
69
+ - Which realm was affected
70
+
71
+ ### 🚀 Full User Lifecycle
72
+ - Create, update, delete users
73
+ - Enable/disable accounts
74
+ - Reset passwords (temporary or permanent)
75
+ - Send verification emails
76
+ - Send password reset emails
77
+ - Bulk import from JSON/CSV
78
+ - Export users
79
+
80
+ </td>
81
+ </tr>
82
+ </table>
83
+
84
+ ---
85
+
86
+ ## Architecture
87
+
88
+ ```
89
+ ┌─────────────────────────────────────────────────────────────────┐
90
+ │ Strapi Admin Panel │
91
+ ├─────────────────────────────────────────────────────────────────┤
92
+ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
93
+ │ │ Realms │ │ Users │ │ Audit Log │ │
94
+ │ │ Config │ │ Management │ │ Viewer │ │
95
+ │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
96
+ │ │ │ │ │
97
+ │ └────────────────┼────────────────┘ │
98
+ │ │ │
99
+ │ ┌───────────────────────▼───────────────────────┐ │
100
+ │ │ Plugin Permission Layer │ │
101
+ │ │ (Realm-based access control) │ │
102
+ │ └───────────────────────┬───────────────────────┘ │
103
+ └──────────────────────────┼──────────────────────────────────────┘
104
+
105
+ ┌───────────────┼───────────────┐
106
+ │ │ │
107
+ ▼ ▼ ▼
108
+ ┌────────────┐ ┌────────────┐ ┌────────────┐
109
+ │ Keycloak │ │ Keycloak │ │ Keycloak │
110
+ │ Realm A │ │ Realm B │ │ Realm C │
111
+ └────────────┘ └────────────┘ └────────────┘
112
+ ```
113
+
114
+ ---
115
+
116
+ ## Installation
117
+
118
+ ```bash
119
+ # Using npm
120
+ npm install strapi-plugin-keycloak-realm-users
121
+
122
+ # Using yarn
123
+ yarn add strapi-plugin-keycloak-realm-users
124
+ ```
125
+
126
+ ---
127
+
128
+ ## Configuration
129
+
130
+ ### 1. Enable the Plugin
131
+
132
+ ```javascript
133
+ // config/plugins.js
134
+ module.exports = {
135
+ 'strapi-plugin-keycloak-realm-users': {
136
+ enabled: true,
137
+ },
138
+ };
139
+ ```
140
+
141
+ ### 2. Configure Keycloak Client
142
+
143
+ For each Keycloak realm you want to manage, you'll need a **service account client** with the following configuration:
144
+
145
+ <details>
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**
177
+
178
+ </details>
179
+
180
+ ---
181
+
182
+ ## Usage
183
+
184
+ ### Adding a Realm
185
+
186
+ 1. Navigate to **Settings** → **Keycloak Realm Users**
187
+ 2. Click **Create Realm**
188
+ 3. Fill in the connection details:
189
+
190
+ | Field | Description | Example |
191
+ |-------|-------------|---------|
192
+ | Name | Unique identifier (lowercase, hyphens) | `production-users` |
193
+ | Display Name | Human-readable name | `Production Users` |
194
+ | Server URL | Keycloak base URL | `https://keycloak.example.com` |
195
+ | Realm Name | The Keycloak realm name | `my-realm` |
196
+ | Client ID | Service account client ID | `strapi-admin` |
197
+ | Client Secret | Client credentials secret | `xxxxx-xxxxx-xxxxx` |
198
+ | Color | UI accent color | `#4945ff` |
199
+
200
+ 4. Click **Test Connection** to verify
201
+ 5. Click **Save**
202
+
203
+ ### Managing Users
204
+
205
+ Once a realm is configured, you can:
206
+
207
+ - **View Users**: Click "Manage Users" on any realm card
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
216
+
217
+ ### Assigning Realm Admins
218
+
219
+ Super admins can assign other Strapi users to manage specific realms:
220
+
221
+ 1. Open a realm's settings
222
+ 2. Go to the **Admins** tab
223
+ 3. Click **Add Admin**
224
+ 4. Select a Strapi user
225
+ 5. Configure their permissions:
226
+
227
+ ```
228
+ ┌───────────────────────────────────────────────────────────────┐
229
+ │ Admin: john@example.com │
230
+ ├───────────────────────────────────────────────────────────────┤
231
+ │ ☑ Can Read ☑ Can Create ☐ Can Delete │
232
+ │ ☑ Can Update ☐ Can Reset Password │
233
+ │ ☐ Can Manage Roles │
234
+ └───────────────────────────────────────────────────────────────┘
235
+ ```
236
+
237
+ ---
238
+
239
+ ## API Reference
240
+
241
+ The plugin exposes a REST API for programmatic access.
242
+
243
+ ### Realms
244
+
245
+ | Method | Endpoint | Description |
246
+ |--------|----------|-------------|
247
+ | `GET` | `/api/keycloak-realm-users/realms` | List all accessible realms |
248
+ | `GET` | `/api/keycloak-realm-users/realms/:id` | Get realm details |
249
+ | `POST` | `/api/keycloak-realm-users/realms` | Create realm (super admin) |
250
+ | `PUT` | `/api/keycloak-realm-users/realms/:id` | Update realm (super admin) |
251
+ | `DELETE` | `/api/keycloak-realm-users/realms/:id` | Delete realm (super admin) |
252
+ | `POST` | `/api/keycloak-realm-users/realms/:id/test` | Test realm connection |
253
+
254
+ ### Users
255
+
256
+ | Method | Endpoint | Description |
257
+ |--------|----------|-------------|
258
+ | `GET` | `/api/keycloak-realm-users/realms/:id/users` | List users (paginated) |
259
+ | `GET` | `/api/keycloak-realm-users/realms/:id/users/:userId` | Get user details |
260
+ | `POST` | `/api/keycloak-realm-users/realms/:id/users` | Create user |
261
+ | `PUT` | `/api/keycloak-realm-users/realms/:id/users/:userId` | Update user |
262
+ | `DELETE` | `/api/keycloak-realm-users/realms/:id/users/:userId` | Delete user |
263
+
264
+ ### User Actions
265
+
266
+ | Method | Endpoint | Description |
267
+ |--------|----------|-------------|
268
+ | `POST` | `/api/.../users/:userId/reset-password` | Reset user password |
269
+ | `POST` | `/api/.../users/:userId/enable` | Enable user |
270
+ | `POST` | `/api/.../users/:userId/disable` | Disable user |
271
+ | `POST` | `/api/.../users/:userId/send-verify-email` | Send verification email |
272
+ | `POST` | `/api/.../users/:userId/send-reset-password-email` | Send password reset email |
273
+
274
+ ### Roles
275
+
276
+ | Method | Endpoint | Description |
277
+ |--------|----------|-------------|
278
+ | `GET` | `/api/.../realms/:id/roles` | List realm roles |
279
+ | `GET` | `/api/.../users/:userId/roles` | Get user's roles |
280
+ | `POST` | `/api/.../users/:userId/roles` | Assign roles |
281
+ | `DELETE` | `/api/.../users/:userId/roles` | Remove roles |
282
+
283
+ ### Bulk Operations
284
+
285
+ | Method | Endpoint | Description |
286
+ |--------|----------|-------------|
287
+ | `POST` | `/api/.../realms/:id/users/import` | Bulk import users |
288
+ | `GET` | `/api/.../realms/:id/users/export` | Export all users |
289
+
290
+ ### Audit Log
291
+
292
+ | Method | Endpoint | Description |
293
+ |--------|----------|-------------|
294
+ | `GET` | `/api/keycloak-realm-users/audit` | Query audit logs |
295
+
296
+ ---
297
+
298
+ ## Permissions
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
320
+
321
+ The plugin integrates with Strapi's Role-Based Access Control system. You can configure permissions under **Settings** → **Roles** → **[Role Name]** → **Keycloak Realm Users**.
322
+
323
+ ---
324
+
325
+ ## Data Model
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
376
+
377
+ <details>
378
+ <summary><strong>403 Forbidden when testing connection</strong></summary>
379
+
380
+ This usually means the Keycloak client doesn't have the required roles.
381
+
382
+ **Solution**: Go to your Keycloak client → Service Account Roles → Assign roles from `realm-management`:
383
+ - `view-realm`
384
+ - `view-users`
385
+ - `manage-users`
386
+ - `query-users`
387
+
388
+ </details>
389
+
390
+ <details>
391
+ <summary><strong>Invalid client secret error</strong></summary>
392
+
393
+ The client secret may have changed or been entered incorrectly.
394
+
395
+ **Solution**:
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
399
+
400
+ </details>
401
+
402
+ <details>
403
+ <summary><strong>Connection works but users fail to load</strong></summary>
404
+
405
+ Test connection only verifies basic realm access. User operations require additional permissions.
406
+
407
+ **Solution**: Ensure your client has `view-users` and `query-users` roles from `realm-management`.
408
+
409
+ </details>
410
+
411
+ ---
412
+
413
+ ## Compatibility
414
+
415
+ | Strapi Version | Plugin Version | Keycloak Version |
416
+ |----------------|----------------|------------------|
417
+ | 5.x | 1.x | 17+ (recommended: 22+) |
418
+
419
+ > **Note**: Keycloak versions below 17 use a different URL structure (`/auth/...`). This plugin is designed for Keycloak 17+ which removed the `/auth` prefix.
420
+
421
+ ---
422
+
423
+ ## Development
424
+
425
+ ### Setup
426
+
427
+ ```bash
428
+ # Clone the repository
429
+ git clone https://github.com/your-org/strapi-plugin-keycloak-realm-users
430
+
431
+ # Install dependencies
432
+ npm install
433
+ ```
434
+
435
+ ### Testing
436
+
437
+ The plugin includes a comprehensive test suite with ~95% code coverage on services and utilities.
438
+
439
+ ```bash
440
+ # Run all tests
441
+ npm test
442
+
443
+ # Run tests in watch mode
444
+ npm run test:watch
445
+
446
+ # Run tests with coverage report
447
+ npm run test:coverage
448
+ ```
449
+
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
462
+
463
+ ---
464
+
465
+ ## Contributing
466
+
467
+ Contributions are welcome! Please read our contributing guidelines before submitting a PR.
468
+
469
+ **Before submitting:**
470
+ 1. Ensure all tests pass: `npm test`
471
+ 2. Maintain or improve code coverage: `npm run test:coverage`
472
+ 3. Add JSDoc documentation for any new public APIs
473
+ 4. Follow the existing code style and patterns
474
+
475
+ ---
476
+
477
+ ## License
478
+
479
+ MIT License - see [LICENSE](LICENSE) for details.
480
+
481
+ ---
482
+
483
+ <p align="center">
484
+ <sub>Built with ❤️ for the Strapi Community</sub>
485
+ </p>