@owlmeans/iam 0.1.18-rc.6 → 0.1.18-rc.8

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.
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
3
  "package": "@owlmeans/iam",
4
- "version": "0.1.18-rc.6",
5
- "generatedAt": "2026-08-18T14:48:00.513Z",
4
+ "version": "0.1.18-rc.8",
5
+ "generatedAt": "2026-08-24T21:14:00.118Z",
6
6
  "canonicalRepo": "https://github.com/owlmeans/common",
7
7
  "entries": [
8
8
  {
@@ -23,6 +23,9 @@ Provider-agnostic IAM abstraction. Defines `IamService` interface and related ty
23
23
  | `IamPermissionDefinition` | type | Declared permission `{ name, resource, action?, resourceScoped?, title? }` |
24
24
  | `IamGrantArgs` | type | `{ resources?: string[] }` — present = resource-scoped grant form |
25
25
  | `IamGrant` | type | `{ profileId, clientId, permission, resources? }` |
26
+ | `IamUser` | type | End-user of an entity `{ profileId, email?, name?, role, disabled?, grantCount? }` |
27
+ | `IamUserInvite` | type | `{ email, name?, role? }` — find-or-create args |
28
+ | `IamUserUpdate` | type | `{ name?, role?, disabled? }` |
26
29
  | `hasPermission` | fn | `(auth, permission, { scope?, resourceId? }?)` — checks `Authorization.permissions` PermissionSet[]; an unscoped set satisfies a resourceId check |
27
30
  | `DEFAULT_ALIAS` | const | Default service alias `'iam-service'` |
28
31
  | `IAM_MODE_KEYCLOAK` | const | `'keycloak'` |
@@ -62,8 +65,15 @@ interface IamService extends InitializedService {
62
65
 
63
66
  // Provision an OIDC client for a tenant and return its credentials.
64
67
  // options.redirectUris hardens the client; always pass them (see "Issuer & redirect URIs").
68
+ // MUST refuse an existing record owned by another entity — see "A client id is a global name".
65
69
  ensureClient: (entityId: string, clientId: string, options?: IamClientOptions) => Promise<IamClient>
66
70
 
71
+ // Reserve a free client id without provisioning it; false when anyone else holds it.
72
+ claimClient: (entityId: string, clientId: string) => Promise<boolean>
73
+
74
+ // Release a client id and everything keyed by it (called when a project/slot is deleted).
75
+ deleteClient: (entityId: string, clientId: string) => Promise<void>
76
+
67
77
  // Provision a named permission on a client resource; returns the resource name
68
78
  ensurePermission: (entityId: string, clientId: string, resource?: string, args?: IamPermissionArgs) => Promise<string>
69
79
 
@@ -83,9 +93,49 @@ interface IamService extends InitializedService {
83
93
 
84
94
  // List grants for the client, optionally for one subject
85
95
  listGrants: (entityId: string, clientId: string, profileId?: string) => Promise<IamGrant[]>
96
+
97
+ // --- End-user management (customer-wide users, shared per entityId) ---
98
+
99
+ // Every end-user of the entity. clientId scopes the reported grantCount — it does NOT filter.
100
+ listUsers: (entityId: string, clientId?: string) => Promise<IamUser[]>
101
+ getUser: (entityId: string, profileId: string) => Promise<IamUser | null>
102
+ // Find-or-create by email — the one way an end-user record comes into existence.
103
+ inviteUser: (entityId: string, invite: IamUserInvite) => Promise<IamUser>
104
+ updateUser: (entityId: string, profileId: string, update: IamUserUpdate) => Promise<IamUser>
105
+ removeUser: (entityId: string, profileId: string) => Promise<void>
86
106
  }
87
107
  ```
88
108
 
109
+ ## End-users are customer-wide
110
+
111
+ An end-user belongs to the **entity**, not to a project: one customer's users are shared across every
112
+ project they own. `listUsers` therefore returns the entity's whole set and `clientId` only scopes the
113
+ reported `grantCount` to one project's client. Do not reintroduce a per-client filter — a person who
114
+ has authenticated against a project but holds no grant there is still that project's user, and the
115
+ screen that hands out grants is exactly where they have to be visible.
116
+
117
+ `inviteUser` is idempotent by email, which is what lets an invitation and a first sign-in converge on
118
+ one record instead of accumulating twins. Backends that have no user store of their own (keycloak,
119
+ where the customer manages realm users in its console) throw `IamUnsupported('user-management')` from
120
+ all five methods; callers turn that into an "external console" fallback rather than an error.
121
+
122
+ ## A client id is a global name
123
+
124
+ A provider resolves a client from the bare `client_id` a relying party sends — the adapter gets no
125
+ tenant context — so the id is unique across the whole deployment, not per entity, and the store
126
+ cannot namespace it on a consumer's behalf. Uniqueness has to be *in the id*.
127
+
128
+ - Compose it with the owning entity in it. A name derived from a project's own name alone lets two
129
+ organizations share one registration: one secret, one redirect-URI list, one permission-definition
130
+ set, and one grant namespace, because `PermissionSet.scope` is that same string.
131
+ - `ensureClient` refuses a record belonging to another entity rather than returning it. The failure
132
+ is deliberate — a loud provisioning error is the only alternative to a silent cross-tenant handover.
133
+ - Assign an id **once** and reserve it with `claimClient`. Whatever a consumer derives ids from
134
+ (a project alias, a slug) may later be released and re-used by a sibling, so only the registry can
135
+ say whether an id is free. `deleteClient` gives it back, or a deleted project's name is burned.
136
+ - Backends whose clients are already per-tenant (keycloak realms) satisfy this by construction:
137
+ `claimClient` returns true and `deleteClient` may be `IamUnsupported`.
138
+
89
139
  ## `IamClient.realm` field
90
140
 
91
141
  `realm` is set by the provider to the entity ID. Use it instead of accessing internal properties:
package/build/types.d.ts CHANGED
@@ -104,7 +104,31 @@ export interface IamService extends InitializedService {
104
104
  * misconfiguration is loud instead of yielding a silently wrong issuer.
105
105
  */
106
106
  getIssuerUrl: (entityId: string) => Promise<string>;
107
+ /**
108
+ * Find-or-create the entity's OIDC client.
109
+ *
110
+ * A client id is globally unique — a provider resolves it from the bare `client_id` a relying
111
+ * party sends, with no tenant context — so an implementation MUST refuse an existing record
112
+ * that belongs to a different entity (`IamClientError('client:entity-mismatch')`) rather than
113
+ * returning it. Silently adopting one hands the caller another tenant's secret and overwrites
114
+ * that tenant's redirect URIs.
115
+ */
107
116
  ensureClient: (entityId: string, clientId: string, options?: IamClientOptions) => Promise<IamClient>;
117
+ /**
118
+ * Reserve a client id for the entity without provisioning it, so a caller can find a free name
119
+ * before committing to it. Returns false when the id is already taken — by this entity or any
120
+ * other — and true when the reservation is now held.
121
+ *
122
+ * This exists because the id is minted from a name that may later be released (a project alias
123
+ * moves when its hostname is refused), so the naming index cannot answer whether an id is free.
124
+ * The registry is the only authority.
125
+ */
126
+ claimClient: (entityId: string, clientId: string) => Promise<boolean>;
127
+ /**
128
+ * Release a client id and everything keyed by it. Called when a project or slot is deleted —
129
+ * without it a recreated project can inherit a stale registration.
130
+ */
131
+ deleteClient: (entityId: string, clientId: string) => Promise<void>;
108
132
  /**
109
133
  * Ensures a permission/resource exists in the entity's client.
110
134
  * Returns the canonical resource name (e.g. "res--action" or "res").
@@ -130,8 +154,11 @@ export interface IamService extends InitializedService {
130
154
  /** Lists grants for the entity's client, optionally for a single subject. */
131
155
  listGrants: (entityId: string, clientId: string, profileId?: string) => Promise<IamGrant[]>;
132
156
  /**
133
- * Lists the entity's end-users. With clientId, narrows to users holding at least
134
- * one grant for that client (per-project view).
157
+ * Lists the entity's end-users. End-users are customer-wide — shared across every project of
158
+ * the entity — so `clientId` scopes the reported `grantCount` to one project's client and does
159
+ * **not** filter the set: a user who has authenticated against a project but holds no grant
160
+ * there is still that project's user, and the screen that manages grants is exactly where they
161
+ * must be visible.
135
162
  */
136
163
  listUsers: (entityId: string, clientId?: string) => Promise<IamUser[]>;
137
164
  /** Loads a single end-user by subject id, or null when absent. */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owlmeans/iam",
3
- "version": "0.1.18-rc.6",
3
+ "version": "0.1.18-rc.8",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -25,7 +25,7 @@
25
25
  "@owlmeans/auth": "^0.1.18-rc.6",
26
26
  "@owlmeans/context": "^0.1.18-rc.6",
27
27
  "@owlmeans/error": "^0.1.18-rc.6",
28
- "@owlmeans/oidc": "^0.1.18-rc.6"
28
+ "@owlmeans/oidc": "^0.1.18-rc.7"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@owlmeans/dep-config": "workspace:*",
package/src/types.ts CHANGED
@@ -120,8 +120,35 @@ export interface IamService extends InitializedService {
120
120
  getIssuerUrl: (entityId: string) => Promise<string>
121
121
 
122
122
  // --- Provisioning (agent → story development) ---
123
+
124
+ /**
125
+ * Find-or-create the entity's OIDC client.
126
+ *
127
+ * A client id is globally unique — a provider resolves it from the bare `client_id` a relying
128
+ * party sends, with no tenant context — so an implementation MUST refuse an existing record
129
+ * that belongs to a different entity (`IamClientError('client:entity-mismatch')`) rather than
130
+ * returning it. Silently adopting one hands the caller another tenant's secret and overwrites
131
+ * that tenant's redirect URIs.
132
+ */
123
133
  ensureClient: (entityId: string, clientId: string, options?: IamClientOptions) => Promise<IamClient>
124
134
 
135
+ /**
136
+ * Reserve a client id for the entity without provisioning it, so a caller can find a free name
137
+ * before committing to it. Returns false when the id is already taken — by this entity or any
138
+ * other — and true when the reservation is now held.
139
+ *
140
+ * This exists because the id is minted from a name that may later be released (a project alias
141
+ * moves when its hostname is refused), so the naming index cannot answer whether an id is free.
142
+ * The registry is the only authority.
143
+ */
144
+ claimClient: (entityId: string, clientId: string) => Promise<boolean>
145
+
146
+ /**
147
+ * Release a client id and everything keyed by it. Called when a project or slot is deleted —
148
+ * without it a recreated project can inherit a stale registration.
149
+ */
150
+ deleteClient: (entityId: string, clientId: string) => Promise<void>
151
+
125
152
  /**
126
153
  * Ensures a permission/resource exists in the entity's client.
127
154
  * Returns the canonical resource name (e.g. "res--action" or "res").
@@ -178,8 +205,11 @@ export interface IamService extends InitializedService {
178
205
  // --- End-user management (customer-wide users, shared per entityId) ---
179
206
 
180
207
  /**
181
- * Lists the entity's end-users. With clientId, narrows to users holding at least
182
- * one grant for that client (per-project view).
208
+ * Lists the entity's end-users. End-users are customer-wide — shared across every project of
209
+ * the entity — so `clientId` scopes the reported `grantCount` to one project's client and does
210
+ * **not** filter the set: a user who has authenticated against a project but holds no grant
211
+ * there is still that project's user, and the screen that manages grants is exactly where they
212
+ * must be visible.
183
213
  */
184
214
  listUsers: (entityId: string, clientId?: string) => Promise<IamUser[]>
185
215