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.
- package/LICENSE +21 -0
- package/README.md +485 -0
- package/__tests__/constants.test.mjs +207 -0
- package/__tests__/mocks/strapi.mjs +182 -0
- package/__tests__/services/audit-log.test.mjs +283 -0
- package/__tests__/services/keycloak-client.test.mjs +651 -0
- package/__tests__/services/permission.test.mjs +374 -0
- package/__tests__/services/realm.test.mjs +415 -0
- package/__tests__/services/user.test.mjs +487 -0
- package/__tests__/utils/errors.test.mjs +109 -0
- package/admin/src/components/Initializer.jsx +14 -0
- package/admin/src/components/RealmBadge.jsx +17 -0
- package/admin/src/constants.js +14 -0
- package/admin/src/hooks/useAuditLogs.js +142 -0
- package/admin/src/hooks/useKeycloakRoles.js +182 -0
- package/admin/src/hooks/useKeycloakUsers.js +477 -0
- package/admin/src/hooks/useRealmAdmins.js +249 -0
- package/admin/src/hooks/useRealms.js +269 -0
- package/admin/src/index.js +46 -0
- package/admin/src/pages/App.jsx +21 -0
- package/admin/src/pages/AuditPage/index.jsx +213 -0
- package/admin/src/pages/RealmsPage/RealmEditPage.jsx +791 -0
- package/admin/src/pages/RealmsPage/RealmListPage.jsx +231 -0
- package/admin/src/pages/RealmsPage/index.jsx +7 -0
- package/admin/src/pages/UsersPage/UserEditPage.jsx +313 -0
- package/admin/src/pages/UsersPage/UserListPage.jsx +437 -0
- package/admin/src/pages/UsersPage/index.jsx +7 -0
- package/admin/src/pluginId.js +2 -0
- package/admin/src/translations/en.json +77 -0
- package/admin/src/translations/fr.json +77 -0
- package/babel.config.cjs +17 -0
- package/coverage/clover.xml +422 -0
- package/coverage/coverage-final.json +8 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +146 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +210 -0
- package/coverage/lcov-report/src/bootstrap.js.html +346 -0
- package/coverage/lcov-report/src/config/index.html +116 -0
- package/coverage/lcov-report/src/config/index.js.html +106 -0
- package/coverage/lcov-report/src/constants.js.html +850 -0
- package/coverage/lcov-report/src/content-types/audit-log/index.html +116 -0
- package/coverage/lcov-report/src/content-types/audit-log/index.js.html +94 -0
- package/coverage/lcov-report/src/content-types/index.html +116 -0
- package/coverage/lcov-report/src/content-types/index.js.html +112 -0
- package/coverage/lcov-report/src/content-types/realm-admin/index.html +116 -0
- package/coverage/lcov-report/src/content-types/realm-admin/index.js.html +94 -0
- package/coverage/lcov-report/src/content-types/realm-config/index.html +116 -0
- package/coverage/lcov-report/src/content-types/realm-config/index.js.html +94 -0
- package/coverage/lcov-report/src/controllers/audit.js.html +517 -0
- package/coverage/lcov-report/src/controllers/index.html +161 -0
- package/coverage/lcov-report/src/controllers/index.js.html +112 -0
- package/coverage/lcov-report/src/controllers/realm.js.html +1057 -0
- package/coverage/lcov-report/src/controllers/user.js.html +1324 -0
- package/coverage/lcov-report/src/destroy.js.html +100 -0
- package/coverage/lcov-report/src/index.html +116 -0
- package/coverage/lcov-report/src/policies/can-access-realm.js.html +163 -0
- package/coverage/lcov-report/src/policies/index.html +146 -0
- package/coverage/lcov-report/src/policies/index.js.html +106 -0
- package/coverage/lcov-report/src/policies/is-authenticated.js.html +100 -0
- package/coverage/lcov-report/src/register.js.html +106 -0
- package/coverage/lcov-report/src/routes/admin.js.html +844 -0
- package/coverage/lcov-report/src/routes/index.html +131 -0
- package/coverage/lcov-report/src/routes/index.js.html +109 -0
- package/coverage/lcov-report/src/services/audit-log.js.html +673 -0
- package/coverage/lcov-report/src/services/index.html +176 -0
- package/coverage/lcov-report/src/services/index.js.html +124 -0
- package/coverage/lcov-report/src/services/keycloak-client.js.html +2359 -0
- package/coverage/lcov-report/src/services/permission.js.html +955 -0
- package/coverage/lcov-report/src/services/realm.js.html +1207 -0
- package/coverage/lcov-report/src/services/user.js.html +1924 -0
- package/coverage/lcov-report/src/utils/errors.js.html +274 -0
- package/coverage/lcov-report/src/utils/index.html +116 -0
- package/coverage/lcov-report/src/utils/index.js.html +103 -0
- package/coverage/lcov.info +804 -0
- package/dist/_chunks/App-BaKrvCeS.mjs +1975 -0
- package/dist/_chunks/App-DO6syS77.js +1975 -0
- package/dist/_chunks/en-Li-XBDe9.mjs +72 -0
- package/dist/_chunks/en-aCyfgNfr.js +72 -0
- package/dist/_chunks/fr-Cj33Q8jI.js +72 -0
- package/dist/_chunks/fr-vLrXph-Z.mjs +72 -0
- package/dist/_chunks/index-DwDO4-0C.js +69 -0
- package/dist/_chunks/index-jTVd7LdQ.mjs +70 -0
- package/dist/admin/index.js +3 -0
- package/dist/admin/index.mjs +4 -0
- package/dist/server/index.js +3003 -0
- package/dist/server/index.mjs +3004 -0
- package/jest.config.cjs +50 -0
- package/package.json +55 -0
- package/server/src/bootstrap.js +87 -0
- package/server/src/config/index.js +7 -0
- package/server/src/constants.js +255 -0
- package/server/src/content-types/audit-log/index.js +3 -0
- package/server/src/content-types/audit-log/schema.json +61 -0
- package/server/src/content-types/index.js +9 -0
- package/server/src/content-types/realm-admin/index.js +3 -0
- package/server/src/content-types/realm-admin/schema.json +45 -0
- package/server/src/content-types/realm-config/index.js +3 -0
- package/server/src/content-types/realm-config/schema.json +56 -0
- package/server/src/controllers/audit.js +144 -0
- package/server/src/controllers/index.js +9 -0
- package/server/src/controllers/realm.js +324 -0
- package/server/src/controllers/user.js +413 -0
- package/server/src/destroy.js +5 -0
- package/server/src/index.js +21 -0
- package/server/src/policies/can-access-realm.js +26 -0
- package/server/src/policies/index.js +7 -0
- package/server/src/policies/is-authenticated.js +5 -0
- package/server/src/register.js +7 -0
- package/server/src/routes/admin.js +253 -0
- package/server/src/routes/index.js +8 -0
- package/server/src/services/audit-log.js +196 -0
- package/server/src/services/index.js +13 -0
- package/server/src/services/keycloak-client.js +758 -0
- package/server/src/services/permission.js +290 -0
- package/server/src/services/realm.js +374 -0
- package/server/src/services/user.js +613 -0
- package/server/src/utils/errors.js +63 -0
- 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>
|