@fabrika/auth 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 +6 -5
- package/src/app-schema.ts +7 -0
- package/src/index.ts +2 -2
- package/src/rpc-http.ts +64 -0
- package/types/src/app-schema.d.ts +628 -0
- package/types/src/client.d.ts +28 -0
- package/types/src/errors.d.ts +43 -0
- package/types/src/iam.d.ts +112 -0
- package/types/src/index.d.ts +20 -0
- package/types/src/membership.d.ts +46 -0
- package/types/src/provision.d.ts +37 -0
- package/types/src/request.d.ts +10 -0
- package/types/src/rpc-http.d.ts +147 -0
- package/types/src/scope.d.ts +18 -0
- package/types/src/types.d.ts +78 -0
- package/types/src/verify.d.ts +29 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fabrika/auth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0-cloudflare.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -12,12 +12,13 @@
|
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
14
14
|
"src",
|
|
15
|
-
"!src/**/__tests__/**"
|
|
15
|
+
"!src/**/__tests__/**",
|
|
16
|
+
"types"
|
|
16
17
|
],
|
|
17
18
|
"exports": {
|
|
18
19
|
".": {
|
|
19
20
|
"bun": "./src/index.ts",
|
|
20
|
-
"types": "./src/index.ts",
|
|
21
|
+
"types": "./types/src/index.d.ts",
|
|
21
22
|
"default": "./src/index.ts"
|
|
22
23
|
}
|
|
23
24
|
},
|
|
@@ -27,8 +28,8 @@
|
|
|
27
28
|
},
|
|
28
29
|
"dependencies": {
|
|
29
30
|
"zod": "^3.25.76",
|
|
30
|
-
"@fabrika/auth-core": "0.
|
|
31
|
-
"@fabrika/jwks": "0.
|
|
31
|
+
"@fabrika/auth-core": "0.9.0-cloudflare.2",
|
|
32
|
+
"@fabrika/jwks": "0.9.0-cloudflare.2",
|
|
32
33
|
"jose": "^5.9.0"
|
|
33
34
|
}
|
|
34
35
|
}
|
package/src/app-schema.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
LOCALES,
|
|
8
8
|
mailTemplateProblems,
|
|
9
9
|
type MessageKind,
|
|
10
|
+
terminalIdentifyProblem,
|
|
10
11
|
WORKLOAD_NAME,
|
|
11
12
|
} from '@fabrika/auth-core'
|
|
12
13
|
import { z } from 'zod'
|
|
@@ -230,6 +231,12 @@ const appSchemaShape = z.object({
|
|
|
230
231
|
.optional(),
|
|
231
232
|
members: z.object({ manage: z.string().min(1), list: z.string().min(1) }).optional(),
|
|
232
233
|
directory: z.literal('labels').optional(),
|
|
234
|
+
terminal: z.object({
|
|
235
|
+
identify: z.string().superRefine((value, ctx) => {
|
|
236
|
+
const problem = terminalIdentifyProblem(value)
|
|
237
|
+
if (problem !== null) ctx.addIssue({ code: 'custom', message: `the terminal's identification path ${problem}` })
|
|
238
|
+
}),
|
|
239
|
+
}).strict().optional(),
|
|
233
240
|
})
|
|
234
241
|
|
|
235
242
|
/** One message's templates by language, each refused with the same rule the contract build applies. */
|
package/src/index.ts
CHANGED
|
@@ -19,8 +19,8 @@ export type { AuthCarrier } from './types'
|
|
|
19
19
|
// The HTTP transport for the SAME `IamRpc` contract, for a runtime with no Cloudflare service binding
|
|
20
20
|
// (a long-running Bun/Node process). Drops into anywhere a binding goes — `createIam`, `IamClient`,
|
|
21
21
|
// `env.IAM` — because the contract is unchanged and only the transport differs.
|
|
22
|
-
export { DecodedIamMembership, HttpIamMembership, HttpIamRpc, IamTransportError } from './rpc-http'
|
|
23
|
-
export type { IamMembershipMethod } from './rpc-http'
|
|
22
|
+
export { DecodedIamMembership, DecodedIamTerminals, HttpIamMembership, HttpIamRpc, HttpIamTerminals, IamTransportError } from './rpc-http'
|
|
23
|
+
export type { IamMembershipMethod, IamTerminalMethod } from './rpc-http'
|
|
24
24
|
// The membership operations an application requests on its caller's behalf (scopes, members, share links).
|
|
25
25
|
export { createIamMembership, IamMembership } from './membership'
|
|
26
26
|
export type { IamMembershipEnv, MembershipRequestCaller } from './membership'
|
package/src/rpc-http.ts
CHANGED
|
@@ -44,9 +44,13 @@
|
|
|
44
44
|
import type {
|
|
45
45
|
ApproveDeviceAuthorizationInput,
|
|
46
46
|
ApproveDeviceAuthorizationResult,
|
|
47
|
+
AssertIdentityInput,
|
|
48
|
+
AssertIdentityResult,
|
|
47
49
|
AssignMemberInput,
|
|
48
50
|
AssignMemberResult,
|
|
49
51
|
AuditInput,
|
|
52
|
+
CancelIdentificationInput,
|
|
53
|
+
CancelIdentificationResult,
|
|
50
54
|
CreateScopeInput,
|
|
51
55
|
CreateScopeResult,
|
|
52
56
|
DenyDeviceAuthorizationResult,
|
|
@@ -54,8 +58,11 @@ import type {
|
|
|
54
58
|
FindMemberResult,
|
|
55
59
|
IamMembershipRpc,
|
|
56
60
|
IamRpc,
|
|
61
|
+
IamTerminalRpc,
|
|
57
62
|
InspectDeviceAuthorizationInput,
|
|
58
63
|
InspectDeviceAuthorizationResult,
|
|
64
|
+
InspectIdentificationInput,
|
|
65
|
+
InspectIdentificationResult,
|
|
59
66
|
IssueKeyInput,
|
|
60
67
|
IssueKeyResult,
|
|
61
68
|
IssueLinkInput,
|
|
@@ -82,6 +89,7 @@ import type {
|
|
|
82
89
|
RevokeLinkResult,
|
|
83
90
|
RevokeMemberInput,
|
|
84
91
|
RevokeMemberResult,
|
|
92
|
+
TerminalFailure,
|
|
85
93
|
} from '@fabrika/auth-core'
|
|
86
94
|
import {
|
|
87
95
|
parseApproveDeviceAuthorizationResult,
|
|
@@ -469,6 +477,62 @@ export class HttpIamMembership extends DecodedIamMembership {
|
|
|
469
477
|
}
|
|
470
478
|
}
|
|
471
479
|
|
|
480
|
+
/** The identification operations, by name, as a transport carries them. */
|
|
481
|
+
export type IamTerminalMethod = keyof IamTerminalRpc
|
|
482
|
+
|
|
483
|
+
const inspectIdentificationSuccessSchema = z.object({
|
|
484
|
+
...okEnvelope,
|
|
485
|
+
terminal: z.object({ id: z.string().min(1), label: z.string().min(1) }),
|
|
486
|
+
expiresAt: z.number().finite(),
|
|
487
|
+
})
|
|
488
|
+
const assertIdentitySuccessSchema = z.object({ ...okEnvelope, completionUrl: z.string().url() })
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* `IamTerminalRpc` over any transport that answers each call with a JSON-shaped body: `HttpIamTerminals`, or a Workers
|
|
492
|
+
* binding to IAM's application entrypoint (ADR-0067). A body that breaks the contract is `IamTransportError`.
|
|
493
|
+
*/
|
|
494
|
+
export class DecodedIamTerminals implements IamTerminalRpc {
|
|
495
|
+
readonly #call: (method: IamTerminalMethod, input: unknown) => Promise<unknown>
|
|
496
|
+
|
|
497
|
+
constructor(call: (method: IamTerminalMethod, input: unknown) => Promise<unknown>) {
|
|
498
|
+
this.#call = call
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
async inspectIdentification(input: InspectIdentificationInput): Promise<InspectIdentificationResult> {
|
|
502
|
+
const body = await this.#call('inspectIdentification', input)
|
|
503
|
+
return readTerminalFailure(body) ?? decode(inspectIdentificationSuccessSchema, body, 'inspectIdentification')
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
async assertIdentity(input: AssertIdentityInput): Promise<AssertIdentityResult> {
|
|
507
|
+
const body = await this.#call('assertIdentity', input)
|
|
508
|
+
return readTerminalFailure(body) ?? decode(assertIdentitySuccessSchema, body, 'assertIdentity')
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
async cancelIdentification(input: CancelIdentificationInput): Promise<CancelIdentificationResult> {
|
|
512
|
+
const body = await this.#call('cancelIdentification', input)
|
|
513
|
+
return readTerminalFailure(body) ?? decode(revokedSuccessSchema, body, 'cancelIdentification')
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* `IamTerminalRpc` over IAM's membership transport, `POST {origin}/membership/<method>`, with the application's own
|
|
519
|
+
* membership transport key, which pins the asserting application.
|
|
520
|
+
*/
|
|
521
|
+
export class HttpIamTerminals extends DecodedIamTerminals {
|
|
522
|
+
constructor(options: HttpIamRpcOptions) {
|
|
523
|
+
const endpoint = transportEndpoint(options, '/membership/')
|
|
524
|
+
super((method, input) => callJson(endpoint, method, input))
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
const TERMINAL_REASONS = ['missing_token', 'invalid_token', 'not_allowed', 'not_found', 'invalid_principal'] as const
|
|
529
|
+
|
|
530
|
+
/** An identification refusal off the wire. An unknown reason degrades to `not_allowed`, never to an allow. */
|
|
531
|
+
function readTerminalFailure(body: unknown): TerminalFailure | null {
|
|
532
|
+
const reason = readFailure(body)
|
|
533
|
+
return reason === null ? null : { ok: false, reason: oneOf(reason, TERMINAL_REASONS, 'not_allowed') }
|
|
534
|
+
}
|
|
535
|
+
|
|
472
536
|
/** The five delegation-path failure reasons `issueKey` / `revokeKey` / `listPrincipals` share. */
|
|
473
537
|
const ISSUE_REASONS = ['missing_token', 'invalid_token', 'unknown_principal', 'disabled', 'not_allowed'] as const
|
|
474
538
|
|