@spinajs/rbac-http-admin 2.0.490 → 2.0.494
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 +110 -110
- package/lib/tsconfig.cjs.tsbuildinfo +1 -1
- package/lib/tsconfig.mjs.tsbuildinfo +1 -1
- package/package.json +73 -71
package/README.md
CHANGED
|
@@ -1,110 +1,110 @@
|
|
|
1
|
-
# `@spinajs/rbac-http-admin`
|
|
2
|
-
|
|
3
|
-
Administrative HTTP API for user accounts: listing and editing users, roles, passwords, two-factor
|
|
4
|
-
authentication, bans, login lockouts and live sessions.
|
|
5
|
-
|
|
6
|
-
Every route sits behind `AuthorizedPolicy` plus a route-level `@Permission` on the `users` resource,
|
|
7
|
-
so an application grants access with ordinary rbac grants:
|
|
8
|
-
|
|
9
|
-
```js
|
|
10
|
-
grants: {
|
|
11
|
-
admin: {
|
|
12
|
-
users: { 'create:any': ['*'], 'read:any': ['*'], 'update:any': ['*'], 'delete:any': ['*'] },
|
|
13
|
-
},
|
|
14
|
-
}
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
## Routes
|
|
18
|
-
|
|
19
|
-
| Method | Path | Permission | What it does |
|
|
20
|
-
| -------- | --------------------------------------------- | ----------- | --------------------------------------------------------- |
|
|
21
|
-
| `GET` | `/users` | `readAny` | Paginated, filterable, sortable list. `X-Total-Count` header |
|
|
22
|
-
| `GET` | `/users/roles` | `readAny` | Roles the caller is allowed to assign |
|
|
23
|
-
| `GET` | `/users/:uuid` | `readAny` | One account |
|
|
24
|
-
| `GET` | `/users/byLogin/:login` | `readAny` | One account, addressed by login |
|
|
25
|
-
| `POST` | `/users` | `createAny` | Create an account ( inactive, temporary password discarded ) |
|
|
26
|
-
| `PATCH` | `/users/:uuid` | `updateAny` | Partial update of login / email / role |
|
|
27
|
-
| `DELETE` | `/users/:uuid` | `deleteAny` | Soft delete + session revocation |
|
|
28
|
-
| `PATCH` | `/users/:uuid/restore` | `deleteAny` | Clear `DeletedAt` |
|
|
29
|
-
| `PATCH` | `/users/role/add/:login` | `updateAny` | Grant a role |
|
|
30
|
-
| `PATCH` | `/users/role/revoke/:login` | `updateAny` | Revoke a role |
|
|
31
|
-
| `GET` | `/users/profile/:login` | `readAny` | Profile through the configured `UserProfileProvider` |
|
|
32
|
-
| `PATCH` | `/users/security/changePassword/:uuid` | `updateAny` | Set a password. Revokes every session of that user |
|
|
33
|
-
| `POST` | `/users/security/password-reset-request/:uuid`| `updateAny` | Issue a reset token and emit `UserPasswordChangeRequest` |
|
|
34
|
-
| `POST` | `/users/security/expire-password/:uuid` | `deleteAny` | Expire the password ( deactivates the account ) |
|
|
35
|
-
| `PATCH` | `/users/security/reset2fa/:uuid` | `updateAny` | Clear the TOTP secret |
|
|
36
|
-
| `POST` | `/users/security/2fa/enable/:uuid` | `updateAny` | Enrol 2FA, returns the enrolment url |
|
|
37
|
-
| `POST` | `/users/security/2fa/disable/:uuid` | `updateAny` | Turn 2FA off |
|
|
38
|
-
| `POST` | `/users/security/activate/:uuid` | `updateAny` | Activate the account |
|
|
39
|
-
| `POST` | `/users/security/deactivate/:uuid` | `deleteAny` | Deactivate + revoke sessions |
|
|
40
|
-
| `POST` | `/users/security/ban/:uuid` | `deleteAny` | Ban for `duration` seconds + revoke sessions |
|
|
41
|
-
| `POST` | `/users/security/unban/:uuid` | `updateAny` | Lift a ban |
|
|
42
|
-
| `POST` | `/users/security/unlock/:uuid` | `updateAny` | Clear a login-throttle lockout |
|
|
43
|
-
| `GET` | `/users/security/sessions/:uuid` | `readAny` | Live sessions, by opaque handle |
|
|
44
|
-
| `DELETE` | `/users/security/sessions/:uuid/:handle` | `updateAny` | Revoke one session |
|
|
45
|
-
| `DELETE` | `/users/security/sessions/:uuid` | `updateAny` | Revoke every session of the user |
|
|
46
|
-
|
|
47
|
-
User metadata is NOT managed here — `@spinajs/rbac-http-user` owns `/user/:uuid/metadata`, which
|
|
48
|
-
validates one entry at a time.
|
|
49
|
-
|
|
50
|
-
## Handing a new account to its owner
|
|
51
|
-
|
|
52
|
-
`POST /users` creates the account **inactive** and throws the generated temporary password away, so a
|
|
53
|
-
created account cannot be logged into yet. The intended flow is:
|
|
54
|
-
|
|
55
|
-
1. `POST /users`
|
|
56
|
-
2. `POST /users/security/password-reset-request/:uuid` — the application delivers the token by
|
|
57
|
-
hooking `UserPasswordChangeRequest`
|
|
58
|
-
3. the user sets their own password through `POST /auth/password/reset`
|
|
59
|
-
4. `POST /users/security/activate/:uuid`
|
|
60
|
-
|
|
61
|
-
## Role guard
|
|
62
|
-
|
|
63
|
-
Role changes are the one operation in this API that can grant MORE than the caller holds, so they run
|
|
64
|
-
through a `RoleGuard` service first. Configure it under `rbac.admin.roleGuard`:
|
|
65
|
-
|
|
66
|
-
```js
|
|
67
|
-
rbac: {
|
|
68
|
-
admin: {
|
|
69
|
-
roleGuard: {
|
|
70
|
-
service: 'DefaultRoleGuard',
|
|
71
|
-
|
|
72
|
-
// reject role names not declared in rbac.grants / rbac.roles
|
|
73
|
-
requireKnownRole: true,
|
|
74
|
-
// rbac.systemRole is never assignable or revocable over HTTP
|
|
75
|
-
protectSystemRole: true,
|
|
76
|
-
// a role whose grants exceed the caller's cannot be handed out
|
|
77
|
-
preventEscalation: true,
|
|
78
|
-
// no self-deactivation, self-deletion, self-ban, self-demotion
|
|
79
|
-
preventSelfLockout: true,
|
|
80
|
-
// never empty a privileged role of its last active holder
|
|
81
|
-
preventLastPrivilegedRemoval: true,
|
|
82
|
-
|
|
83
|
-
// what counts as "privileged" for the two checks above
|
|
84
|
-
privilegedResource: 'users',
|
|
85
|
-
privilegedAction: 'update:any',
|
|
86
|
-
},
|
|
87
|
-
},
|
|
88
|
-
}
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
Replace the whole policy by registering your own class under the `RoleGuard` base and naming it in
|
|
92
|
-
`service`:
|
|
93
|
-
|
|
94
|
-
```ts
|
|
95
|
-
@Injectable(RoleGuard)
|
|
96
|
-
export class MyRoleGuard extends RoleGuard { /* ... */ }
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
## Breaking changes in this release
|
|
100
|
-
|
|
101
|
-
- `activate`, `deactivate` and the forced logout moved off `GET`. They are now
|
|
102
|
-
`POST /users/security/activate/:uuid`, `POST /users/security/deactivate/:uuid` and
|
|
103
|
-
`DELETE /users/security/sessions/:uuid`.
|
|
104
|
-
- `activate` now requires `updateAny` instead of `deleteAny`.
|
|
105
|
-
- `GET /users/:uuid` and `GET /users/byLogin/:login` now require `readAny`. They previously required
|
|
106
|
-
nothing beyond a valid session — any authenticated account could read any other.
|
|
107
|
-
- `PATCH /users/:uuid` no longer accepts `Metadata`, and its body is validated as a partial update
|
|
108
|
-
( `Login`, `Email`, `Role` are all optional, unknown properties are rejected ).
|
|
109
|
-
- Credential-bearing metadata ( password-reset token, 2FA secret, ban and lockout state ) is filtered
|
|
110
|
-
out of every dehydrated user, in this package and everywhere else.
|
|
1
|
+
# `@spinajs/rbac-http-admin`
|
|
2
|
+
|
|
3
|
+
Administrative HTTP API for user accounts: listing and editing users, roles, passwords, two-factor
|
|
4
|
+
authentication, bans, login lockouts and live sessions.
|
|
5
|
+
|
|
6
|
+
Every route sits behind `AuthorizedPolicy` plus a route-level `@Permission` on the `users` resource,
|
|
7
|
+
so an application grants access with ordinary rbac grants:
|
|
8
|
+
|
|
9
|
+
```js
|
|
10
|
+
grants: {
|
|
11
|
+
admin: {
|
|
12
|
+
users: { 'create:any': ['*'], 'read:any': ['*'], 'update:any': ['*'], 'delete:any': ['*'] },
|
|
13
|
+
},
|
|
14
|
+
}
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Routes
|
|
18
|
+
|
|
19
|
+
| Method | Path | Permission | What it does |
|
|
20
|
+
| -------- | --------------------------------------------- | ----------- | --------------------------------------------------------- |
|
|
21
|
+
| `GET` | `/users` | `readAny` | Paginated, filterable, sortable list. `X-Total-Count` header |
|
|
22
|
+
| `GET` | `/users/roles` | `readAny` | Roles the caller is allowed to assign |
|
|
23
|
+
| `GET` | `/users/:uuid` | `readAny` | One account |
|
|
24
|
+
| `GET` | `/users/byLogin/:login` | `readAny` | One account, addressed by login |
|
|
25
|
+
| `POST` | `/users` | `createAny` | Create an account ( inactive, temporary password discarded ) |
|
|
26
|
+
| `PATCH` | `/users/:uuid` | `updateAny` | Partial update of login / email / role |
|
|
27
|
+
| `DELETE` | `/users/:uuid` | `deleteAny` | Soft delete + session revocation |
|
|
28
|
+
| `PATCH` | `/users/:uuid/restore` | `deleteAny` | Clear `DeletedAt` |
|
|
29
|
+
| `PATCH` | `/users/role/add/:login` | `updateAny` | Grant a role |
|
|
30
|
+
| `PATCH` | `/users/role/revoke/:login` | `updateAny` | Revoke a role |
|
|
31
|
+
| `GET` | `/users/profile/:login` | `readAny` | Profile through the configured `UserProfileProvider` |
|
|
32
|
+
| `PATCH` | `/users/security/changePassword/:uuid` | `updateAny` | Set a password. Revokes every session of that user |
|
|
33
|
+
| `POST` | `/users/security/password-reset-request/:uuid`| `updateAny` | Issue a reset token and emit `UserPasswordChangeRequest` |
|
|
34
|
+
| `POST` | `/users/security/expire-password/:uuid` | `deleteAny` | Expire the password ( deactivates the account ) |
|
|
35
|
+
| `PATCH` | `/users/security/reset2fa/:uuid` | `updateAny` | Clear the TOTP secret |
|
|
36
|
+
| `POST` | `/users/security/2fa/enable/:uuid` | `updateAny` | Enrol 2FA, returns the enrolment url |
|
|
37
|
+
| `POST` | `/users/security/2fa/disable/:uuid` | `updateAny` | Turn 2FA off |
|
|
38
|
+
| `POST` | `/users/security/activate/:uuid` | `updateAny` | Activate the account |
|
|
39
|
+
| `POST` | `/users/security/deactivate/:uuid` | `deleteAny` | Deactivate + revoke sessions |
|
|
40
|
+
| `POST` | `/users/security/ban/:uuid` | `deleteAny` | Ban for `duration` seconds + revoke sessions |
|
|
41
|
+
| `POST` | `/users/security/unban/:uuid` | `updateAny` | Lift a ban |
|
|
42
|
+
| `POST` | `/users/security/unlock/:uuid` | `updateAny` | Clear a login-throttle lockout |
|
|
43
|
+
| `GET` | `/users/security/sessions/:uuid` | `readAny` | Live sessions, by opaque handle |
|
|
44
|
+
| `DELETE` | `/users/security/sessions/:uuid/:handle` | `updateAny` | Revoke one session |
|
|
45
|
+
| `DELETE` | `/users/security/sessions/:uuid` | `updateAny` | Revoke every session of the user |
|
|
46
|
+
|
|
47
|
+
User metadata is NOT managed here — `@spinajs/rbac-http-user` owns `/user/:uuid/metadata`, which
|
|
48
|
+
validates one entry at a time.
|
|
49
|
+
|
|
50
|
+
## Handing a new account to its owner
|
|
51
|
+
|
|
52
|
+
`POST /users` creates the account **inactive** and throws the generated temporary password away, so a
|
|
53
|
+
created account cannot be logged into yet. The intended flow is:
|
|
54
|
+
|
|
55
|
+
1. `POST /users`
|
|
56
|
+
2. `POST /users/security/password-reset-request/:uuid` — the application delivers the token by
|
|
57
|
+
hooking `UserPasswordChangeRequest`
|
|
58
|
+
3. the user sets their own password through `POST /auth/password/reset`
|
|
59
|
+
4. `POST /users/security/activate/:uuid`
|
|
60
|
+
|
|
61
|
+
## Role guard
|
|
62
|
+
|
|
63
|
+
Role changes are the one operation in this API that can grant MORE than the caller holds, so they run
|
|
64
|
+
through a `RoleGuard` service first. Configure it under `rbac.admin.roleGuard`:
|
|
65
|
+
|
|
66
|
+
```js
|
|
67
|
+
rbac: {
|
|
68
|
+
admin: {
|
|
69
|
+
roleGuard: {
|
|
70
|
+
service: 'DefaultRoleGuard',
|
|
71
|
+
|
|
72
|
+
// reject role names not declared in rbac.grants / rbac.roles
|
|
73
|
+
requireKnownRole: true,
|
|
74
|
+
// rbac.systemRole is never assignable or revocable over HTTP
|
|
75
|
+
protectSystemRole: true,
|
|
76
|
+
// a role whose grants exceed the caller's cannot be handed out
|
|
77
|
+
preventEscalation: true,
|
|
78
|
+
// no self-deactivation, self-deletion, self-ban, self-demotion
|
|
79
|
+
preventSelfLockout: true,
|
|
80
|
+
// never empty a privileged role of its last active holder
|
|
81
|
+
preventLastPrivilegedRemoval: true,
|
|
82
|
+
|
|
83
|
+
// what counts as "privileged" for the two checks above
|
|
84
|
+
privilegedResource: 'users',
|
|
85
|
+
privilegedAction: 'update:any',
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Replace the whole policy by registering your own class under the `RoleGuard` base and naming it in
|
|
92
|
+
`service`:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
@Injectable(RoleGuard)
|
|
96
|
+
export class MyRoleGuard extends RoleGuard { /* ... */ }
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Breaking changes in this release
|
|
100
|
+
|
|
101
|
+
- `activate`, `deactivate` and the forced logout moved off `GET`. They are now
|
|
102
|
+
`POST /users/security/activate/:uuid`, `POST /users/security/deactivate/:uuid` and
|
|
103
|
+
`DELETE /users/security/sessions/:uuid`.
|
|
104
|
+
- `activate` now requires `updateAny` instead of `deleteAny`.
|
|
105
|
+
- `GET /users/:uuid` and `GET /users/byLogin/:login` now require `readAny`. They previously required
|
|
106
|
+
nothing beyond a valid session — any authenticated account could read any other.
|
|
107
|
+
- `PATCH /users/:uuid` no longer accepts `Metadata`, and its body is validated as a partial update
|
|
108
|
+
( `Login`, `Email`, `Role` are all optional, unknown properties are rejected ).
|
|
109
|
+
- Credential-bearing metadata ( password-reset token, 2FA secret, ban and lockout state ) is filtered
|
|
110
|
+
out of every dehydrated user, in this package and everywhere else.
|