@fabrika/iam-contract 0.8.2 → 0.9.0-cloudflare.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/package.json +7 -5
- package/src/access.ts +3 -0
- package/src/index.ts +160 -13
- package/src/oauth.ts +71 -10
- package/src/password-policy.ts +43 -0
- package/types/src/access.d.ts +27 -0
- package/types/src/index.d.ts +745 -0
- package/types/src/oauth.d.ts +136 -0
- package/types/src/password-policy.d.ts +34 -0
|
@@ -0,0 +1,745 @@
|
|
|
1
|
+
import type { RpcProcedureContract } from '@fabrika/app';
|
|
2
|
+
import type { AppActionDef, AppDelegationDef, AppLinkMountDef, AppMemberItem, AppSchema, AppScopeDef, Locale, PermissionEntry, PermissionSource, PrincipalAffiliation, PrincipalType, RoleDef, WorkloadKind } from '@fabrika/auth-core';
|
|
3
|
+
import type { InstallationBrand } from '@fabrika/proxy-core/brand';
|
|
4
|
+
import type { PasswordPolicyDto, SetPasswordPolicyRequest } from './password-policy';
|
|
5
|
+
/** A plain list response. */
|
|
6
|
+
export interface ListResponse<T> {
|
|
7
|
+
items: T[];
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* A cursor-paginated list. `nextCursor` is the opaque cursor to pass as `before`
|
|
11
|
+
* for the next page; null when there are no more rows.
|
|
12
|
+
*/
|
|
13
|
+
export interface CursorList<T> {
|
|
14
|
+
items: T[];
|
|
15
|
+
nextCursor: string | null;
|
|
16
|
+
}
|
|
17
|
+
/** Derived principal status — invited (unclaimed) → active → disabled. */
|
|
18
|
+
export type PrincipalStatus = 'invited' | 'active' | 'disabled';
|
|
19
|
+
export interface PrincipalListItem {
|
|
20
|
+
id: string;
|
|
21
|
+
type: PrincipalType;
|
|
22
|
+
label: string;
|
|
23
|
+
email: string | null;
|
|
24
|
+
externalId: string | null;
|
|
25
|
+
status: PrincipalStatus;
|
|
26
|
+
/** `external`: a person from outside the organization, who holds only roles declared external (ADR-0051). */
|
|
27
|
+
affiliation: PrincipalAffiliation;
|
|
28
|
+
createdAt: number;
|
|
29
|
+
}
|
|
30
|
+
export interface GrantDto {
|
|
31
|
+
id: string;
|
|
32
|
+
principalId: string;
|
|
33
|
+
/** Named role/policy key; null for an inline grant (then `permissions` is set). */
|
|
34
|
+
roleKey: string | null;
|
|
35
|
+
/** Inline action-pattern set; null for a role-based grant (then `roleKey` is set). */
|
|
36
|
+
permissions: string[] | null;
|
|
37
|
+
/** Scope dimension; null = global (both rise/fall together). */
|
|
38
|
+
scopeType: string | null;
|
|
39
|
+
/** Opaque, app-owned scope value; null = global. */
|
|
40
|
+
scopeValue: string | null;
|
|
41
|
+
/** App id this grant applies to; null = all apps (cross-app). */
|
|
42
|
+
app: string | null;
|
|
43
|
+
grantedBy: string | null;
|
|
44
|
+
expiresAt: number | null;
|
|
45
|
+
createdAt: number;
|
|
46
|
+
/** True when `roleKey` is set but no longer resolves to a known role (zero perms). */
|
|
47
|
+
dangling: boolean;
|
|
48
|
+
}
|
|
49
|
+
export interface PrincipalDetail extends PrincipalListItem {
|
|
50
|
+
/** The mailbox is listed in `IAM_BOOTSTRAP_ADMINS`: an internal user with it is an installation admin. */
|
|
51
|
+
bootstrapMailbox: boolean;
|
|
52
|
+
grants: PrincipalGrantDto[];
|
|
53
|
+
/** Permissions at IAM only. Prefer `access` for the per-application view. */
|
|
54
|
+
permissions: PermissionEntry[];
|
|
55
|
+
access: PrincipalAppAccess[];
|
|
56
|
+
/** Presentation capabilities. Every mutation still checks the caller live. */
|
|
57
|
+
management: {
|
|
58
|
+
account: boolean;
|
|
59
|
+
passwordLinks: boolean;
|
|
60
|
+
audit: boolean;
|
|
61
|
+
};
|
|
62
|
+
activatedAt: number | null;
|
|
63
|
+
disabledAt: number | null;
|
|
64
|
+
authentication: {
|
|
65
|
+
/** OIDC is linked when this user has claimed an identity-provider subject. */
|
|
66
|
+
oidc: {
|
|
67
|
+
state: 'unavailable' | 'unlinked' | 'linked';
|
|
68
|
+
};
|
|
69
|
+
/** Password access is globally opt-in and then enabled per user. */
|
|
70
|
+
password: {
|
|
71
|
+
state: 'unavailable' | 'disabled' | 'pending' | 'enabled';
|
|
72
|
+
delivery: 'email' | 'manual';
|
|
73
|
+
latestAction: {
|
|
74
|
+
purpose: 'enrollment' | 'reset';
|
|
75
|
+
createdAt: number;
|
|
76
|
+
expiresAt: number;
|
|
77
|
+
closedAt: number | null;
|
|
78
|
+
} | null;
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
export interface PrincipalGrantDto extends GrantDto {
|
|
83
|
+
roleName: string | null;
|
|
84
|
+
rolePermissions: string[];
|
|
85
|
+
grantedByLabel: string | null;
|
|
86
|
+
canManage: boolean;
|
|
87
|
+
}
|
|
88
|
+
export interface PrincipalAppAccess {
|
|
89
|
+
app: string;
|
|
90
|
+
/** Resolved by IAM using the same per-app resolver as token issuance; empty for a disabled account. */
|
|
91
|
+
permissions: PermissionEntry[];
|
|
92
|
+
lastSignInAt: number | null;
|
|
93
|
+
}
|
|
94
|
+
export interface InviteRequest {
|
|
95
|
+
email: string;
|
|
96
|
+
/** Omitted: `internal`. An `external` user signs in by password only, and OIDC never claims it. */
|
|
97
|
+
affiliation?: PrincipalAffiliation;
|
|
98
|
+
}
|
|
99
|
+
export interface UpdatePrincipalRequest {
|
|
100
|
+
disabled: boolean;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* A browser session, as an operator sees it. Never the cookie or its hash — a session is addressed
|
|
104
|
+
* by `id`, which is not a credential.
|
|
105
|
+
*/
|
|
106
|
+
export interface SessionDto {
|
|
107
|
+
id: string;
|
|
108
|
+
principalId: string;
|
|
109
|
+
/**
|
|
110
|
+
* How the human proved who they were; `local_dev` is IAM's `LOCAL_DEV_LOGIN` bypass, `terminal_assertion` an
|
|
111
|
+
* application's word about who stands at an enrolled terminal.
|
|
112
|
+
*/
|
|
113
|
+
authenticationMethod: 'oidc' | 'password' | 'local_dev' | 'terminal_assertion';
|
|
114
|
+
/** The app this session is bound to (an ADR-0022 child); null = the IAM session itself. */
|
|
115
|
+
app: string | null;
|
|
116
|
+
/** The IAM session this was derived from; null on an IAM session. Revoking that one revokes this. */
|
|
117
|
+
parentSessionId: string | null;
|
|
118
|
+
/** `active` until it is revoked or its expiry passes. A revoked session reads `revoked`. */
|
|
119
|
+
status: 'active' | 'revoked' | 'expired';
|
|
120
|
+
createdAt: number;
|
|
121
|
+
expiresAt: number;
|
|
122
|
+
revokedAt: number | null;
|
|
123
|
+
/** Why this session cannot be used now, independently of its own stored lifecycle. */
|
|
124
|
+
unavailableReason: 'revoked' | 'expired' | 'parent_ended' | 'account_disabled' | 'method_disabled' | null;
|
|
125
|
+
}
|
|
126
|
+
export interface SessionList extends CursorList<SessionDto> {
|
|
127
|
+
/** App sessions belonging to the sign-ins on this page, when `signInsOnly` is requested. */
|
|
128
|
+
applications: SessionDto[];
|
|
129
|
+
}
|
|
130
|
+
export interface CreateGrantRequest {
|
|
131
|
+
principalId: string;
|
|
132
|
+
/** A named role/policy key — XOR `permissions` (supply exactly one). */
|
|
133
|
+
roleKey?: string;
|
|
134
|
+
/** An inline action-pattern set — XOR `roleKey` (supply exactly one). */
|
|
135
|
+
permissions?: string[];
|
|
136
|
+
/** Scope dimension; null / omitted = global. Both-or-neither with `scopeValue`. */
|
|
137
|
+
scopeType?: string | null;
|
|
138
|
+
/** Opaque, app-owned scope value; null / omitted = global. */
|
|
139
|
+
scopeValue?: string | null;
|
|
140
|
+
/** App id (a registered app id); null / omitted = all apps (cross-app). */
|
|
141
|
+
app?: string | null;
|
|
142
|
+
expiresAt?: number | null;
|
|
143
|
+
}
|
|
144
|
+
/** Change access within its original application, preserving the grant's identity and author. */
|
|
145
|
+
export interface UpdateGrantInput extends Omit<CreateGrantRequest, 'principalId' | 'app'> {
|
|
146
|
+
id: string;
|
|
147
|
+
}
|
|
148
|
+
/** The set of app ids propustka knows about — the choices for a grant's `app`. */
|
|
149
|
+
export interface AppDto {
|
|
150
|
+
id: string;
|
|
151
|
+
/** The name the app's schema declares for people; null when it declares none. */
|
|
152
|
+
displayName: string | null;
|
|
153
|
+
/** One of the installation's own apps (a platform audience): a user administrator grants nothing there (ADR-0058). */
|
|
154
|
+
installation: boolean;
|
|
155
|
+
}
|
|
156
|
+
/** A role available for the calling app — a built-in or a DB row (app/custom). */
|
|
157
|
+
export interface RoleDto extends RoleDef {
|
|
158
|
+
key: string;
|
|
159
|
+
/** 'builtin' (cross-app, e.g. admin), 'app' (reconciled), or 'custom' (admin-made). */
|
|
160
|
+
origin: 'builtin' | 'app' | 'custom';
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* The body of `PUT /admin/apps/:app/schema` — one of the two surviving REST operations, because a
|
|
164
|
+
* deploy step reconciles an app's vocabulary from outside the installation. It IS the core
|
|
165
|
+
* `AppSchema`; `reconcileSchema` in `@fabrika/auth` sends exactly this.
|
|
166
|
+
*/
|
|
167
|
+
export type PutAppSchemaRequest = AppSchema;
|
|
168
|
+
/** GET schema response — the app's scopes, actions, and origin='app' roles. */
|
|
169
|
+
export interface AppSchemaDto {
|
|
170
|
+
app: string;
|
|
171
|
+
scopes: AppScopeDef[];
|
|
172
|
+
actions: AppActionDef[];
|
|
173
|
+
/** role_key -> def, origin='app' only (reconciled from code). */
|
|
174
|
+
roles: Record<string, RoleDef>;
|
|
175
|
+
/** Share-link mounts; absent when the app declares none. */
|
|
176
|
+
links?: Record<string, AppLinkMountDef>;
|
|
177
|
+
/** Endpoints that may spend membership authority; absent when the app declares none. */
|
|
178
|
+
delegations?: Record<string, AppDelegationDef>;
|
|
179
|
+
/** The language IAM speaks to the app's people; absent when the app declares none. */
|
|
180
|
+
locale?: Locale;
|
|
181
|
+
/** The name IAM shows for the app; absent when the app declares none. */
|
|
182
|
+
displayName?: string;
|
|
183
|
+
/** The actions that manage and list the app's own people; absent when the app declares none. */
|
|
184
|
+
members?: {
|
|
185
|
+
manage: string;
|
|
186
|
+
list: string;
|
|
187
|
+
};
|
|
188
|
+
/** `labels` when the app's directory shows labels to `members.list` holders. */
|
|
189
|
+
directory?: 'labels';
|
|
190
|
+
/** The app's identification page at a terminal (ADR-0067); absent when the app declares none. */
|
|
191
|
+
terminal?: {
|
|
192
|
+
identify: string;
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
/** A custom policy (an origin='custom' role row) for an app. */
|
|
196
|
+
export interface PolicyDto {
|
|
197
|
+
app: string;
|
|
198
|
+
key: string;
|
|
199
|
+
name: string;
|
|
200
|
+
description?: string;
|
|
201
|
+
permissions: string[];
|
|
202
|
+
createdAt: number;
|
|
203
|
+
}
|
|
204
|
+
export interface CreatePolicyRequest {
|
|
205
|
+
key: string;
|
|
206
|
+
name: string;
|
|
207
|
+
description?: string;
|
|
208
|
+
permissions: string[];
|
|
209
|
+
}
|
|
210
|
+
export interface UpdatePolicyRequest {
|
|
211
|
+
name: string;
|
|
212
|
+
description?: string;
|
|
213
|
+
permissions: string[];
|
|
214
|
+
}
|
|
215
|
+
/** Metadata view of a service-principal API key (the secret is never returned here). */
|
|
216
|
+
export interface ApiKeyDto {
|
|
217
|
+
principalId: string;
|
|
218
|
+
label: string;
|
|
219
|
+
status: PrincipalStatus;
|
|
220
|
+
grants: GrantDto[];
|
|
221
|
+
createdAt: number;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* One API key with its live credential, as `apiKeys.get` and each row of `apiKeys.list` answer it. Its permissions are
|
|
225
|
+
* its grants, edited with `grants.create` and `grants.delete` by an installation administrator and read again at every
|
|
226
|
+
* token exchange. An IAM older than the list's credential answers list rows without `credential`.
|
|
227
|
+
*/
|
|
228
|
+
export interface ApiKeyDetail extends ApiKeyDto {
|
|
229
|
+
/** The key's live credential, or null when none is live (a revoked key). */
|
|
230
|
+
credential: ApiKeyCredentialDto | null;
|
|
231
|
+
}
|
|
232
|
+
export interface ApiKeyCredentialDto {
|
|
233
|
+
/** The app the key mints tokens for; null = every app. A grant at another app never reaches the key's token. */
|
|
234
|
+
app: string | null;
|
|
235
|
+
expiresAt: number | null;
|
|
236
|
+
}
|
|
237
|
+
export interface ProvisionApiKeyRequest {
|
|
238
|
+
label: string;
|
|
239
|
+
type: 'service';
|
|
240
|
+
/** A named role/policy key — XOR `permissions` (supply exactly one). */
|
|
241
|
+
roleKey?: string;
|
|
242
|
+
/** An inline action-pattern set — XOR `roleKey` (supply exactly one). */
|
|
243
|
+
permissions?: string[];
|
|
244
|
+
/** Scope dimension; null / omitted = global. Both-or-neither with `scopeValue`. */
|
|
245
|
+
scopeType?: string | null;
|
|
246
|
+
/** Opaque, app-owned scope value; null / omitted = global. */
|
|
247
|
+
scopeValue?: string | null;
|
|
248
|
+
/** App id (a registered app id); null / omitted = all apps. */
|
|
249
|
+
app?: string | null;
|
|
250
|
+
expiresAt?: number | null;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Provisioning result. `apiKey` (a `px_…` credential bound to the new service principal) is shown
|
|
254
|
+
* exactly ONCE — copy it now, it is not retrievable later. Carried as a bearer (or a declared
|
|
255
|
+
* header) directly to apps on the propustka-native path (`mintFromKey`), no Cloudflare Access in
|
|
256
|
+
* front.
|
|
257
|
+
*/
|
|
258
|
+
export interface ProvisionApiKeyResponse {
|
|
259
|
+
principalId: string;
|
|
260
|
+
apiKey: string;
|
|
261
|
+
}
|
|
262
|
+
/** Rotation result — new key shown once; principal + grants unchanged, old key stops working. */
|
|
263
|
+
export interface RotateApiKeyResponse {
|
|
264
|
+
principalId: string;
|
|
265
|
+
apiKey: string;
|
|
266
|
+
}
|
|
267
|
+
/** Metadata only — never the token hash or plaintext. A share link is an anonymous credential. */
|
|
268
|
+
export interface ShareLinkListItem {
|
|
269
|
+
id: string;
|
|
270
|
+
label: string | null;
|
|
271
|
+
/** The app this link mints for. Never null on a link issued after the app binding (SEC-2). */
|
|
272
|
+
app: string | null;
|
|
273
|
+
issuedBy: string | null;
|
|
274
|
+
expiresAt: number | null;
|
|
275
|
+
revokedAt: number | null;
|
|
276
|
+
createdAt: number;
|
|
277
|
+
/** Frozen inline grants — matched by `permits` (action + optional scope), not exact resource. */
|
|
278
|
+
grants: {
|
|
279
|
+
action: string;
|
|
280
|
+
scope: {
|
|
281
|
+
type: string;
|
|
282
|
+
value: string;
|
|
283
|
+
} | null;
|
|
284
|
+
}[];
|
|
285
|
+
}
|
|
286
|
+
export interface IssueShareLinkRequest {
|
|
287
|
+
/**
|
|
288
|
+
* The app the link mints for. REQUIRED: an anonymous credential's grants are frozen at issue, so
|
|
289
|
+
* the app they were delegated against is the only thing that keeps them from being spent at every
|
|
290
|
+
* other app behind the proxy.
|
|
291
|
+
*/
|
|
292
|
+
app: string;
|
|
293
|
+
/** Each grant is delegation-checked against the issuer on its `scope` (omitted → global). */
|
|
294
|
+
grants: {
|
|
295
|
+
action: string;
|
|
296
|
+
scope?: {
|
|
297
|
+
type: string;
|
|
298
|
+
value: string;
|
|
299
|
+
} | null;
|
|
300
|
+
}[];
|
|
301
|
+
label?: string;
|
|
302
|
+
/** Absolute expiry (unix seconds). REQUIRED, and at most `MAX_KEY_LIFETIME_SECONDS` ahead: no key is permanent. */
|
|
303
|
+
expiresAt: number;
|
|
304
|
+
}
|
|
305
|
+
/** Issued share-link result — the plaintext `px_` token returned ONCE. */
|
|
306
|
+
export interface IssuedShareLinkResponse {
|
|
307
|
+
id: string;
|
|
308
|
+
token: string;
|
|
309
|
+
}
|
|
310
|
+
export interface AuditEventDto {
|
|
311
|
+
id: string;
|
|
312
|
+
requestId: string;
|
|
313
|
+
principalId: string | null;
|
|
314
|
+
principalLabel: string;
|
|
315
|
+
credentialId: string | null;
|
|
316
|
+
app: string;
|
|
317
|
+
action: string;
|
|
318
|
+
resourceType: string;
|
|
319
|
+
resourceId: string | null;
|
|
320
|
+
diff: unknown;
|
|
321
|
+
metadata: unknown;
|
|
322
|
+
createdAt: number;
|
|
323
|
+
}
|
|
324
|
+
export interface AuthLogDto {
|
|
325
|
+
id: number;
|
|
326
|
+
requestId: string;
|
|
327
|
+
app: string;
|
|
328
|
+
/** A login attempt or a mint (`authenticate`), or the end of a session (`logout`). */
|
|
329
|
+
kind: 'authenticate' | 'logout';
|
|
330
|
+
principalId: string | null;
|
|
331
|
+
credentialId: string | null;
|
|
332
|
+
decision: 'allow' | 'deny';
|
|
333
|
+
reason: string | null;
|
|
334
|
+
/** The login opened a session of an installation administrator. */
|
|
335
|
+
privileged: boolean;
|
|
336
|
+
createdAt: number;
|
|
337
|
+
}
|
|
338
|
+
export interface MeDto {
|
|
339
|
+
id: string;
|
|
340
|
+
type: PrincipalType;
|
|
341
|
+
label: string;
|
|
342
|
+
permissions: PermissionEntry[];
|
|
343
|
+
}
|
|
344
|
+
export interface OkResponse {
|
|
345
|
+
ok: true;
|
|
346
|
+
}
|
|
347
|
+
/** Every admin list takes the same page coordinates: an opaque `before` cursor and a row `limit`. */
|
|
348
|
+
export interface PageInput {
|
|
349
|
+
before?: string;
|
|
350
|
+
limit?: number;
|
|
351
|
+
}
|
|
352
|
+
export interface ListPrincipalsInput extends PageInput {
|
|
353
|
+
type?: PrincipalType;
|
|
354
|
+
status?: PrincipalStatus;
|
|
355
|
+
q?: string;
|
|
356
|
+
}
|
|
357
|
+
export type ListApiKeysInput = PageInput;
|
|
358
|
+
export interface ListShareLinksInput extends PageInput {
|
|
359
|
+
/** Only links minting for this app. */
|
|
360
|
+
app?: string;
|
|
361
|
+
/** Revoked links are hidden by default; the console asks for them explicitly. */
|
|
362
|
+
includeRevoked?: boolean;
|
|
363
|
+
}
|
|
364
|
+
export interface RotateApiKeyInput extends ApiKeyIdInput {
|
|
365
|
+
/**
|
|
366
|
+
* New absolute expiry (unix seconds), or `null` for none. OMITTED carries the replaced
|
|
367
|
+
* credential's expiry forward — rotation replaces a secret, it does not extend a lifetime.
|
|
368
|
+
*/
|
|
369
|
+
expiresAt?: number | null;
|
|
370
|
+
}
|
|
371
|
+
/** Every procedure that names a principal keys it as `principalId`; a bare `id` names some other resource. */
|
|
372
|
+
export interface PrincipalIdInput {
|
|
373
|
+
principalId: string;
|
|
374
|
+
}
|
|
375
|
+
export interface ListSessionsInput extends PageInput {
|
|
376
|
+
/** Whose sessions to list. */
|
|
377
|
+
principalId: string;
|
|
378
|
+
signInsOnly?: boolean;
|
|
379
|
+
}
|
|
380
|
+
export interface SessionIdInput {
|
|
381
|
+
id: string;
|
|
382
|
+
}
|
|
383
|
+
/** How many rows the call actually revoked; an already-revoked session is not counted again. */
|
|
384
|
+
export interface RevokedSessionsResponse {
|
|
385
|
+
revoked: number;
|
|
386
|
+
}
|
|
387
|
+
export interface UpdatePrincipalInput extends UpdatePrincipalRequest, PrincipalIdInput {
|
|
388
|
+
}
|
|
389
|
+
/** Password action sent by email, or a one-time URL shown only in this response. */
|
|
390
|
+
export type PasswordActionDelivery = {
|
|
391
|
+
delivery: 'email';
|
|
392
|
+
email: string;
|
|
393
|
+
expiresAt: number;
|
|
394
|
+
} | {
|
|
395
|
+
delivery: 'manual';
|
|
396
|
+
url: string;
|
|
397
|
+
expiresAt: number;
|
|
398
|
+
};
|
|
399
|
+
export interface GrantIdInput {
|
|
400
|
+
id: string;
|
|
401
|
+
}
|
|
402
|
+
export interface AppInput {
|
|
403
|
+
app: string;
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* The public origins IAM will hand this app a session at (ADR-0022). Declarative: the whole set is
|
|
407
|
+
* stated, so removing one is the same call as adding one and a stale entry cannot survive a deploy.
|
|
408
|
+
*/
|
|
409
|
+
export interface SetReturnOriginsRequest {
|
|
410
|
+
app: string;
|
|
411
|
+
origins: string[];
|
|
412
|
+
}
|
|
413
|
+
export interface ReturnOriginsDto {
|
|
414
|
+
app: string;
|
|
415
|
+
/** Canonicalized: lower-cased scheme and host, default port dropped, no path. */
|
|
416
|
+
origins: string[];
|
|
417
|
+
}
|
|
418
|
+
export interface ListRolesInput {
|
|
419
|
+
app?: string | null;
|
|
420
|
+
}
|
|
421
|
+
export interface CreatePolicyInput {
|
|
422
|
+
app: string;
|
|
423
|
+
policy: CreatePolicyRequest;
|
|
424
|
+
}
|
|
425
|
+
export interface UpdatePolicyInput {
|
|
426
|
+
app: string;
|
|
427
|
+
key: string;
|
|
428
|
+
policy: UpdatePolicyRequest;
|
|
429
|
+
}
|
|
430
|
+
export interface PolicyIdInput {
|
|
431
|
+
app: string;
|
|
432
|
+
key: string;
|
|
433
|
+
}
|
|
434
|
+
export interface ApiKeyIdInput {
|
|
435
|
+
principalId: string;
|
|
436
|
+
}
|
|
437
|
+
export interface ShareLinkIdInput {
|
|
438
|
+
id: string;
|
|
439
|
+
}
|
|
440
|
+
export interface ListAuditInput {
|
|
441
|
+
resourceType?: string;
|
|
442
|
+
resourceId?: string;
|
|
443
|
+
principalId?: string;
|
|
444
|
+
/** The person affected by the change, distinct from `principalId` (the actor). */
|
|
445
|
+
subjectPrincipalId?: string;
|
|
446
|
+
action?: string;
|
|
447
|
+
/**
|
|
448
|
+
* Leave out the admin reads (`iam.admin.access`), which IAM writes for every `/admin/*` request, so a feed of what
|
|
449
|
+
* changed reads changes and not the reads that page through it. An IAM older than this field ignores it.
|
|
450
|
+
*/
|
|
451
|
+
changesOnly?: boolean;
|
|
452
|
+
requestId?: string;
|
|
453
|
+
before?: string;
|
|
454
|
+
limit?: number;
|
|
455
|
+
}
|
|
456
|
+
export interface ListAuthLogInput {
|
|
457
|
+
principalId?: string;
|
|
458
|
+
requestId?: string;
|
|
459
|
+
decision?: 'allow' | 'deny';
|
|
460
|
+
before?: string;
|
|
461
|
+
limit?: number;
|
|
462
|
+
}
|
|
463
|
+
type RpcProcedure<TInput, TOutput> = RpcProcedureContract<TInput, TOutput>;
|
|
464
|
+
/** Browser-safe typed contract for the IAM administration API. */
|
|
465
|
+
/**
|
|
466
|
+
* Issue a fresh key for one workload of an application (ADR-0022 "Principal kinds"). The key resolves to the actions
|
|
467
|
+
* the app's reconciled schema declares for the workload. Every other key of the workload is revoked except `keep`.
|
|
468
|
+
*/
|
|
469
|
+
export interface IssueWorkloadKeyRequest {
|
|
470
|
+
/** The IAM application id `<app>@<env>`. */
|
|
471
|
+
app: string;
|
|
472
|
+
/**
|
|
473
|
+
* `public` is a public procedure, named by its endpoint id; `app` is the connector of the application named `name`,
|
|
474
|
+
* which consumes an export of `app`.
|
|
475
|
+
*/
|
|
476
|
+
kind: WorkloadKind;
|
|
477
|
+
name: string;
|
|
478
|
+
/** Absolute expiry (unix seconds), after now and at most 30 days ahead. */
|
|
479
|
+
expiresAt: number;
|
|
480
|
+
/**
|
|
481
|
+
* The credential id of the key the caller has recorded as active, which stays valid until the caller replaces it; null
|
|
482
|
+
* when it has none. A key issued earlier and never recorded is an orphan, and is revoked.
|
|
483
|
+
*/
|
|
484
|
+
keep: string | null;
|
|
485
|
+
}
|
|
486
|
+
/** The plaintext key is returned once. */
|
|
487
|
+
export interface IssueWorkloadKeyResponse {
|
|
488
|
+
key: string;
|
|
489
|
+
credentialId: string;
|
|
490
|
+
principalId: string;
|
|
491
|
+
expiresAt: number;
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Revoke every key of one workload of `app`, the key a rotation kept included: what Control asks when a consumer stops
|
|
495
|
+
* importing from `app`. A workload with no principal has nothing to revoke.
|
|
496
|
+
*/
|
|
497
|
+
export interface RevokeWorkloadKeysRequest {
|
|
498
|
+
app: string;
|
|
499
|
+
kind: WorkloadKind;
|
|
500
|
+
name: string;
|
|
501
|
+
}
|
|
502
|
+
export interface RevokeWorkloadKeysResponse {
|
|
503
|
+
revoked: number;
|
|
504
|
+
}
|
|
505
|
+
/**
|
|
506
|
+
* Issue a fresh membership transport key for one application environment (ADR-0022 rule 6). The key authenticates
|
|
507
|
+
* IAM's `/membership/*` surface and pins the application id; it carries no authority. Every other key of the
|
|
508
|
+
* application environment is deleted except `keep`.
|
|
509
|
+
*/
|
|
510
|
+
export interface IssueMembershipKeyRequest {
|
|
511
|
+
/** The IAM application id `<app>@<env>`. */
|
|
512
|
+
app: string;
|
|
513
|
+
/** Absolute expiry (unix seconds), after now and at most 30 days ahead. */
|
|
514
|
+
expiresAt: number;
|
|
515
|
+
/** The id of the key the caller has recorded as active, which stays valid until the caller replaces it; null when it has none. */
|
|
516
|
+
keep: string | null;
|
|
517
|
+
}
|
|
518
|
+
/** The issued key, shown once. `id` is what a later issuance keeps. */
|
|
519
|
+
export interface IssueMembershipKeyResponse {
|
|
520
|
+
key: string;
|
|
521
|
+
id: string;
|
|
522
|
+
expiresAt: number;
|
|
523
|
+
}
|
|
524
|
+
/** An application that may assert a person on a terminal, with the action patterns of the person that survive there. */
|
|
525
|
+
export interface TerminalAsserterDto {
|
|
526
|
+
app: string;
|
|
527
|
+
ceiling: string[];
|
|
528
|
+
}
|
|
529
|
+
/**
|
|
530
|
+
* An enrolled browser, as an operator sees it. Its own grants are ordinary grants on `terminalId`, which is its service
|
|
531
|
+
* principal; the cookie is never shown.
|
|
532
|
+
*/
|
|
533
|
+
export interface TerminalDto {
|
|
534
|
+
terminalId: string;
|
|
535
|
+
label: string;
|
|
536
|
+
/** The administrator who enrolled it; null once that principal is gone. */
|
|
537
|
+
enrolledBy: string | null;
|
|
538
|
+
/** Seconds a person's session on it lasts. */
|
|
539
|
+
sessionTtl: number;
|
|
540
|
+
asserters: TerminalAsserterDto[];
|
|
541
|
+
status: 'active' | 'revoked';
|
|
542
|
+
createdAt: number;
|
|
543
|
+
lastSeenAt: number | null;
|
|
544
|
+
revokedAt: number | null;
|
|
545
|
+
}
|
|
546
|
+
export type ListTerminalsInput = PageInput;
|
|
547
|
+
export interface TerminalIdInput {
|
|
548
|
+
terminalId: string;
|
|
549
|
+
}
|
|
550
|
+
/** Replace a terminal's whole profile. The ceiling is empty by default: the person brings only their identity. */
|
|
551
|
+
export interface SetTerminalProfileRequest extends TerminalIdInput {
|
|
552
|
+
label: string;
|
|
553
|
+
sessionTtl: number;
|
|
554
|
+
asserters: TerminalAsserterDto[];
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* An application whose people the caller administers: it holds the application's `members.manage` globally there.
|
|
558
|
+
* `roles` are the application's global roles the caller may grant, those whose every action it holds itself.
|
|
559
|
+
*/
|
|
560
|
+
export interface AdministeredAppDto {
|
|
561
|
+
app: string;
|
|
562
|
+
displayName: string | null;
|
|
563
|
+
roles: {
|
|
564
|
+
key: string;
|
|
565
|
+
name: string;
|
|
566
|
+
permissions: string[];
|
|
567
|
+
}[];
|
|
568
|
+
}
|
|
569
|
+
export interface AppPeopleInput {
|
|
570
|
+
app: string;
|
|
571
|
+
/** The previous page's `next`. */
|
|
572
|
+
after?: string;
|
|
573
|
+
}
|
|
574
|
+
/** One page of the application's people, as its administrator sees them: labels, addresses and last sign-ins. */
|
|
575
|
+
export interface AppPeopleDto {
|
|
576
|
+
app: string;
|
|
577
|
+
members: AppMemberItem[];
|
|
578
|
+
next: string | null;
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
581
|
+
* Give a person who already has an IAM principal one of the application's global roles, by its address (the people
|
|
582
|
+
* list answers each person's). An address IAM knows no person for is a 404: an IAM administrator invites people, an
|
|
583
|
+
* application's administrator does not. Holding the role already answers the same.
|
|
584
|
+
*/
|
|
585
|
+
export interface GrantAppRoleRequest {
|
|
586
|
+
app: string;
|
|
587
|
+
role: string;
|
|
588
|
+
email: string;
|
|
589
|
+
}
|
|
590
|
+
export interface GrantAppRoleResponse {
|
|
591
|
+
principalId: string;
|
|
592
|
+
role: string;
|
|
593
|
+
/** False when the person held the role already. */
|
|
594
|
+
granted: boolean;
|
|
595
|
+
}
|
|
596
|
+
/** Remove the global grant of `role` from a person. Repeating it answers the same. */
|
|
597
|
+
export interface RevokeAppRoleRequest {
|
|
598
|
+
app: string;
|
|
599
|
+
role: string;
|
|
600
|
+
principalId: string;
|
|
601
|
+
}
|
|
602
|
+
export interface RevokeAppRoleResponse {
|
|
603
|
+
/** False when the person held no such grant. */
|
|
604
|
+
revoked: boolean;
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* The installation's client logo on fabrika's own pages (ADR-0066): IAM's sign-in, account and invitation pages, and the
|
|
608
|
+
* proxy's error pages on every application host. `null` shows the fabrika mark. An installation serves one client, so
|
|
609
|
+
* this is one setting of the installation, kept by IAM.
|
|
610
|
+
*/
|
|
611
|
+
export interface InstallationBrandDto {
|
|
612
|
+
brand: InstallationBrand | null;
|
|
613
|
+
/** When it was last set or cleared, in epoch seconds; null when it never was. */
|
|
614
|
+
updatedAt: number | null;
|
|
615
|
+
}
|
|
616
|
+
export interface SetInstallationBrandRequest {
|
|
617
|
+
brand: InstallationBrand;
|
|
618
|
+
}
|
|
619
|
+
export interface IamAdminRpcContract {
|
|
620
|
+
me: RpcProcedure<void, MeDto>;
|
|
621
|
+
principals: {
|
|
622
|
+
list: RpcProcedure<ListPrincipalsInput, CursorList<PrincipalListItem>>;
|
|
623
|
+
get: RpcProcedure<PrincipalIdInput, PrincipalDetail>;
|
|
624
|
+
invite: RpcProcedure<InviteRequest, PrincipalListItem>;
|
|
625
|
+
update: RpcProcedure<UpdatePrincipalInput, PrincipalListItem>;
|
|
626
|
+
/**
|
|
627
|
+
* Make an external user internal, revoking its sessions and pending password actions. A bootstrap mailbox becomes
|
|
628
|
+
* an installation admin. There is no way back; promoting an internal principal is a 409.
|
|
629
|
+
*/
|
|
630
|
+
promote: RpcProcedure<PrincipalIdInput, PrincipalListItem>;
|
|
631
|
+
};
|
|
632
|
+
/**
|
|
633
|
+
* Sessions an operator no longer trusts. Revoking an IAM session also ends every app session
|
|
634
|
+
* derived from it — a child is only valid while its parent is — so this is one call, not a sweep.
|
|
635
|
+
*/
|
|
636
|
+
sessions: {
|
|
637
|
+
list: RpcProcedure<ListSessionsInput, SessionList>;
|
|
638
|
+
revoke: RpcProcedure<SessionIdInput, RevokedSessionsResponse>;
|
|
639
|
+
revokeAll: RpcProcedure<PrincipalIdInput, RevokedSessionsResponse>;
|
|
640
|
+
};
|
|
641
|
+
passwords: {
|
|
642
|
+
issueEnrollment: RpcProcedure<PrincipalIdInput, PasswordActionDelivery>;
|
|
643
|
+
issueReset: RpcProcedure<PrincipalIdInput, PasswordActionDelivery>;
|
|
644
|
+
disable: RpcProcedure<PrincipalIdInput, OkResponse>;
|
|
645
|
+
};
|
|
646
|
+
grants: {
|
|
647
|
+
/** A role grant the principal already holds — same role, scope and app — answers 409 naming it. */
|
|
648
|
+
create: RpcProcedure<CreateGrantRequest, GrantDto>;
|
|
649
|
+
update: RpcProcedure<UpdateGrantInput, GrantDto>;
|
|
650
|
+
delete: RpcProcedure<GrantIdInput, OkResponse>;
|
|
651
|
+
};
|
|
652
|
+
connections: {
|
|
653
|
+
list: RpcProcedure<ListSessionsInput, CursorList<UserConnectionDto>>;
|
|
654
|
+
revoke: RpcProcedure<GrantIdInput, OkResponse>;
|
|
655
|
+
};
|
|
656
|
+
apps: {
|
|
657
|
+
list: RpcProcedure<void, ListResponse<AppDto>>;
|
|
658
|
+
getSchema: RpcProcedure<AppInput, AppSchemaDto>;
|
|
659
|
+
setReturnOrigins: RpcProcedure<SetReturnOriginsRequest, ReturnOriginsDto>;
|
|
660
|
+
};
|
|
661
|
+
roles: {
|
|
662
|
+
list: RpcProcedure<ListRolesInput, ListResponse<RoleDto>>;
|
|
663
|
+
};
|
|
664
|
+
policies: {
|
|
665
|
+
list: RpcProcedure<AppInput, ListResponse<PolicyDto>>;
|
|
666
|
+
create: RpcProcedure<CreatePolicyInput, PolicyDto>;
|
|
667
|
+
update: RpcProcedure<UpdatePolicyInput, PolicyDto>;
|
|
668
|
+
delete: RpcProcedure<PolicyIdInput, OkResponse>;
|
|
669
|
+
};
|
|
670
|
+
apiKeys: {
|
|
671
|
+
list: RpcProcedure<ListApiKeysInput, CursorList<ApiKeyDetail>>;
|
|
672
|
+
get: RpcProcedure<ApiKeyIdInput, ApiKeyDetail>;
|
|
673
|
+
provision: RpcProcedure<ProvisionApiKeyRequest, ProvisionApiKeyResponse>;
|
|
674
|
+
rotate: RpcProcedure<RotateApiKeyInput, RotateApiKeyResponse>;
|
|
675
|
+
revoke: RpcProcedure<ApiKeyIdInput, OkResponse>;
|
|
676
|
+
};
|
|
677
|
+
workloads: {
|
|
678
|
+
issueKey: RpcProcedure<IssueWorkloadKeyRequest, IssueWorkloadKeyResponse>;
|
|
679
|
+
revokeKeys: RpcProcedure<RevokeWorkloadKeysRequest, RevokeWorkloadKeysResponse>;
|
|
680
|
+
};
|
|
681
|
+
membershipKeys: {
|
|
682
|
+
issue: RpcProcedure<IssueMembershipKeyRequest, IssueMembershipKeyResponse>;
|
|
683
|
+
};
|
|
684
|
+
shareLinks: {
|
|
685
|
+
list: RpcProcedure<ListShareLinksInput, CursorList<ShareLinkListItem>>;
|
|
686
|
+
issue: RpcProcedure<IssueShareLinkRequest, IssuedShareLinkResponse>;
|
|
687
|
+
revoke: RpcProcedure<ShareLinkIdInput, OkResponse>;
|
|
688
|
+
};
|
|
689
|
+
audit: {
|
|
690
|
+
list: RpcProcedure<ListAuditInput, CursorList<AuditEventDto>>;
|
|
691
|
+
listAuthLog: RpcProcedure<ListAuthLogInput, CursorList<AuthLogDto>>;
|
|
692
|
+
};
|
|
693
|
+
/**
|
|
694
|
+
* Enrolled terminals. A browser is enrolled at IAM's `/auth/terminals/enroll`, never here. Revoking a terminal ends
|
|
695
|
+
* every session issued on it.
|
|
696
|
+
*/
|
|
697
|
+
terminals: {
|
|
698
|
+
list: RpcProcedure<ListTerminalsInput, CursorList<TerminalDto>>;
|
|
699
|
+
setProfile: RpcProcedure<SetTerminalProfileRequest, TerminalDto>;
|
|
700
|
+
revoke: RpcProcedure<TerminalIdInput, OkResponse>;
|
|
701
|
+
};
|
|
702
|
+
/**
|
|
703
|
+
* An application's own people, administered by whoever holds the application's `members.manage` globally there: no
|
|
704
|
+
* installation admin needed. Each change writes its audit row under the application.
|
|
705
|
+
*/
|
|
706
|
+
appPeople: {
|
|
707
|
+
apps: RpcProcedure<void, ListResponse<AdministeredAppDto>>;
|
|
708
|
+
list: RpcProcedure<AppPeopleInput, AppPeopleDto>;
|
|
709
|
+
grant: RpcProcedure<GrantAppRoleRequest, GrantAppRoleResponse>;
|
|
710
|
+
revoke: RpcProcedure<RevokeAppRoleRequest, RevokeAppRoleResponse>;
|
|
711
|
+
};
|
|
712
|
+
/**
|
|
713
|
+
* The installation's client logo (ADR-0066), an installation administrator's (`iam.admin`) to read and to change. A
|
|
714
|
+
* change writes `iam.brand.update` in its own transaction. IAM's pages show it on their next render; the proxy's
|
|
715
|
+
* pages once Control republishes their manifests.
|
|
716
|
+
*/
|
|
717
|
+
brand: {
|
|
718
|
+
get: RpcProcedure<void, InstallationBrandDto>;
|
|
719
|
+
set: RpcProcedure<SetInstallationBrandRequest, InstallationBrandDto>;
|
|
720
|
+
clear: RpcProcedure<void, InstallationBrandDto>;
|
|
721
|
+
};
|
|
722
|
+
/**
|
|
723
|
+
* The installation's minimum password length (ADR-0020), an installation administrator's (`iam.admin`) to read and to
|
|
724
|
+
* change. A change writes `iam.password_policy.update` in its own transaction and applies to the next password set,
|
|
725
|
+
* reset or chosen at an invitation; stored passwords stay as they are.
|
|
726
|
+
*/
|
|
727
|
+
passwordPolicy: {
|
|
728
|
+
get: RpcProcedure<void, PasswordPolicyDto>;
|
|
729
|
+
set: RpcProcedure<SetPasswordPolicyRequest, PasswordPolicyDto>;
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
export interface UserConnectionDto {
|
|
733
|
+
id: string;
|
|
734
|
+
clientId: string;
|
|
735
|
+
app: string;
|
|
736
|
+
resource: string;
|
|
737
|
+
scopes: string[];
|
|
738
|
+
createdAt: number;
|
|
739
|
+
expiresAt: number;
|
|
740
|
+
status: 'active' | 'revoked' | 'expired' | 'unavailable';
|
|
741
|
+
}
|
|
742
|
+
export type { AppActionDef, AppMemberItem, AppSchema, AppScopeDef, PermissionEntry, PermissionSource, PrincipalAffiliation, PrincipalType, RoleDef };
|
|
743
|
+
export * from './access';
|
|
744
|
+
export * from './oauth';
|
|
745
|
+
export * from './password-policy';
|