@amodalai/runtime 0.3.70 → 0.3.71
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/dist/src/auth/__fixtures__/custom-strategy.d.ts +8 -0
- package/dist/src/auth/__fixtures__/custom-strategy.js +27 -0
- package/dist/src/auth/__fixtures__/custom-strategy.js.map +1 -0
- package/dist/src/auth/compose.d.ts +55 -0
- package/dist/src/auth/compose.js +142 -0
- package/dist/src/auth/compose.js.map +1 -0
- package/dist/src/auth/compose.test.d.ts +6 -0
- package/dist/src/auth/compose.test.js +159 -0
- package/dist/src/auth/compose.test.js.map +1 -0
- package/dist/src/auth/config.d.ts +261 -0
- package/dist/src/auth/config.js +107 -0
- package/dist/src/auth/config.js.map +1 -0
- package/dist/src/auth/config.test.d.ts +6 -0
- package/dist/src/auth/config.test.js +85 -0
- package/dist/src/auth/config.test.js.map +1 -0
- package/dist/src/auth/factory.d.ts +19 -0
- package/dist/src/auth/factory.js +57 -0
- package/dist/src/auth/factory.js.map +1 -0
- package/dist/src/auth/factory.test.d.ts +6 -0
- package/dist/src/auth/factory.test.js +60 -0
- package/dist/src/auth/factory.test.js.map +1 -0
- package/dist/src/auth/index.d.ts +48 -0
- package/dist/src/auth/index.js +19 -0
- package/dist/src/auth/index.js.map +1 -0
- package/dist/src/auth/strategies/amodal.d.ts +36 -0
- package/dist/src/auth/strategies/amodal.js +28 -0
- package/dist/src/auth/strategies/amodal.js.map +1 -0
- package/dist/src/auth/strategies/api-key.d.ts +41 -0
- package/dist/src/auth/strategies/api-key.js +63 -0
- package/dist/src/auth/strategies/api-key.js.map +1 -0
- package/dist/src/auth/strategies/auth-modes.integration.test.d.ts +6 -0
- package/dist/src/auth/strategies/auth-modes.integration.test.js +363 -0
- package/dist/src/auth/strategies/auth-modes.integration.test.js.map +1 -0
- package/dist/src/auth/strategies/cookie.d.ts +41 -0
- package/dist/src/auth/strategies/cookie.js +84 -0
- package/dist/src/auth/strategies/cookie.js.map +1 -0
- package/dist/src/auth/strategies/custom-loader.d.ts +17 -0
- package/dist/src/auth/strategies/custom-loader.js +37 -0
- package/dist/src/auth/strategies/custom-loader.js.map +1 -0
- package/dist/src/auth/strategies/header.d.ts +35 -0
- package/dist/src/auth/strategies/header.js +42 -0
- package/dist/src/auth/strategies/header.js.map +1 -0
- package/dist/src/auth/strategies/jwks.d.ts +38 -0
- package/dist/src/auth/strategies/jwks.js +86 -0
- package/dist/src/auth/strategies/jwks.js.map +1 -0
- package/dist/src/auth/strategies/jwt-secret.d.ts +25 -0
- package/dist/src/auth/strategies/jwt-secret.js +82 -0
- package/dist/src/auth/strategies/jwt-secret.js.map +1 -0
- package/dist/src/auth/strategies/jwt-secret.test.d.ts +6 -0
- package/dist/src/auth/strategies/jwt-secret.test.js +75 -0
- package/dist/src/auth/strategies/jwt-secret.test.js.map +1 -0
- package/dist/src/auth/strategies/none.d.ts +37 -0
- package/dist/src/auth/strategies/none.js +31 -0
- package/dist/src/auth/strategies/none.js.map +1 -0
- package/dist/src/auth/strategies/oidc.d.ts +48 -0
- package/dist/src/auth/strategies/oidc.integration.test.d.ts +6 -0
- package/dist/src/auth/strategies/oidc.integration.test.js +290 -0
- package/dist/src/auth/strategies/oidc.integration.test.js.map +1 -0
- package/dist/src/auth/strategies/oidc.js +284 -0
- package/dist/src/auth/strategies/oidc.js.map +1 -0
- package/dist/src/auth/strategies/oidc.test.d.ts +6 -0
- package/dist/src/auth/strategies/oidc.test.js +111 -0
- package/dist/src/auth/strategies/oidc.test.js.map +1 -0
- package/dist/src/auth/strategies/strategies.test.d.ts +6 -0
- package/dist/src/auth/strategies/strategies.test.js +190 -0
- package/dist/src/auth/strategies/strategies.test.js.map +1 -0
- package/dist/src/auth/types.d.ts +95 -0
- package/dist/src/auth/types.js +7 -0
- package/dist/src/auth/types.js.map +1 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +2 -0
- package/dist/src/index.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +9 -4
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Config-driven auth — discriminated union the agent owner sets in
|
|
8
|
+
* `amodal.json` (or whatever surfaces the runtime through). The host
|
|
9
|
+
* resolves any `env:` references against its secrets store before
|
|
10
|
+
* passing the config to `createAuthStrategy(config)`.
|
|
11
|
+
*
|
|
12
|
+
* {
|
|
13
|
+
* "auth": {
|
|
14
|
+
* "type": "oidc",
|
|
15
|
+
* "issuer": "https://acme.okta.com",
|
|
16
|
+
* ...
|
|
17
|
+
* }
|
|
18
|
+
* }
|
|
19
|
+
*/
|
|
20
|
+
import { z } from 'zod';
|
|
21
|
+
declare const NoneAuthConfigSchema: z.ZodObject<{
|
|
22
|
+
type: z.ZodLiteral<"none">;
|
|
23
|
+
/** Synthesized user id for the anonymous session. Defaults to `'anonymous'`. */
|
|
24
|
+
userId: z.ZodOptional<z.ZodString>;
|
|
25
|
+
}, "strip", z.ZodTypeAny, {
|
|
26
|
+
type: "none";
|
|
27
|
+
userId?: string | undefined;
|
|
28
|
+
}, {
|
|
29
|
+
type: "none";
|
|
30
|
+
userId?: string | undefined;
|
|
31
|
+
}>;
|
|
32
|
+
declare const JwtSecretAuthConfigSchema: z.ZodObject<{
|
|
33
|
+
type: z.ZodLiteral<"jwt_secret">;
|
|
34
|
+
/** Shared HMAC secret used to verify incoming JWTs. */
|
|
35
|
+
secret: z.ZodString;
|
|
36
|
+
/** HMAC algorithm. Defaults to HS256. */
|
|
37
|
+
algorithm: z.ZodOptional<z.ZodEnum<["HS256", "HS384", "HS512"]>>;
|
|
38
|
+
/** Expected `iss` claim. Optional. */
|
|
39
|
+
issuer: z.ZodOptional<z.ZodString>;
|
|
40
|
+
/** Expected `aud` claim. Optional. */
|
|
41
|
+
audience: z.ZodOptional<z.ZodString>;
|
|
42
|
+
}, "strip", z.ZodTypeAny, {
|
|
43
|
+
type: "jwt_secret";
|
|
44
|
+
secret: string;
|
|
45
|
+
issuer?: string | undefined;
|
|
46
|
+
audience?: string | undefined;
|
|
47
|
+
algorithm?: "HS256" | "HS384" | "HS512" | undefined;
|
|
48
|
+
}, {
|
|
49
|
+
type: "jwt_secret";
|
|
50
|
+
secret: string;
|
|
51
|
+
issuer?: string | undefined;
|
|
52
|
+
audience?: string | undefined;
|
|
53
|
+
algorithm?: "HS256" | "HS384" | "HS512" | undefined;
|
|
54
|
+
}>;
|
|
55
|
+
declare const OidcAuthConfigSchema: z.ZodObject<{
|
|
56
|
+
type: z.ZodLiteral<"oidc">;
|
|
57
|
+
/** OIDC issuer URL — the IdP's discovery base (`https://acme.okta.com`). */
|
|
58
|
+
issuer: z.ZodString;
|
|
59
|
+
clientId: z.ZodString;
|
|
60
|
+
clientSecret: z.ZodString;
|
|
61
|
+
/** Where the IdP redirects back after login. Must be registered with the IdP. */
|
|
62
|
+
callbackUrl: z.ZodString;
|
|
63
|
+
/** OAuth scopes to request. Defaults to `['openid', 'email', 'profile']`. */
|
|
64
|
+
scopes: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
65
|
+
/**
|
|
66
|
+
* HMAC secret used to sign the session JWT stored in the runtime's cookie.
|
|
67
|
+
* Distinct from the IdP — this is purely the runtime's session signing key.
|
|
68
|
+
*/
|
|
69
|
+
sessionSecret: z.ZodString;
|
|
70
|
+
/** Cookie name for the session JWT. Defaults to `'amodal_session'`. */
|
|
71
|
+
cookieName: z.ZodOptional<z.ZodString>;
|
|
72
|
+
/** Session TTL in seconds. Defaults to 24h. */
|
|
73
|
+
sessionTtlSeconds: z.ZodOptional<z.ZodNumber>;
|
|
74
|
+
}, "strip", z.ZodTypeAny, {
|
|
75
|
+
type: "oidc";
|
|
76
|
+
issuer: string;
|
|
77
|
+
clientId: string;
|
|
78
|
+
clientSecret: string;
|
|
79
|
+
callbackUrl: string;
|
|
80
|
+
sessionSecret: string;
|
|
81
|
+
scopes?: string[] | undefined;
|
|
82
|
+
cookieName?: string | undefined;
|
|
83
|
+
sessionTtlSeconds?: number | undefined;
|
|
84
|
+
}, {
|
|
85
|
+
type: "oidc";
|
|
86
|
+
issuer: string;
|
|
87
|
+
clientId: string;
|
|
88
|
+
clientSecret: string;
|
|
89
|
+
callbackUrl: string;
|
|
90
|
+
sessionSecret: string;
|
|
91
|
+
scopes?: string[] | undefined;
|
|
92
|
+
cookieName?: string | undefined;
|
|
93
|
+
sessionTtlSeconds?: number | undefined;
|
|
94
|
+
}>;
|
|
95
|
+
declare const HeaderAuthConfigSchema: z.ZodObject<{
|
|
96
|
+
type: z.ZodLiteral<"header">;
|
|
97
|
+
headerName: z.ZodOptional<z.ZodString>;
|
|
98
|
+
}, "strip", z.ZodTypeAny, {
|
|
99
|
+
type: "header";
|
|
100
|
+
headerName?: string | undefined;
|
|
101
|
+
}, {
|
|
102
|
+
type: "header";
|
|
103
|
+
headerName?: string | undefined;
|
|
104
|
+
}>;
|
|
105
|
+
declare const CustomAuthConfigSchema: z.ZodObject<{
|
|
106
|
+
type: z.ZodLiteral<"custom">;
|
|
107
|
+
/**
|
|
108
|
+
* Module path (relative to the agent's runtime directory) whose default
|
|
109
|
+
* export implements the `AuthStrategy` interface. The runtime imports
|
|
110
|
+
* this file at startup and validates the shape.
|
|
111
|
+
*/
|
|
112
|
+
module: z.ZodString;
|
|
113
|
+
}, "strip", z.ZodTypeAny, {
|
|
114
|
+
type: "custom";
|
|
115
|
+
module: string;
|
|
116
|
+
}, {
|
|
117
|
+
type: "custom";
|
|
118
|
+
module: string;
|
|
119
|
+
}>;
|
|
120
|
+
/**
|
|
121
|
+
* "Sign in with Amodal" — verifies platform JWTs minted by the Amodal
|
|
122
|
+
* cloud (or any self-hosted Amodal-equivalent platform). Agent owners on
|
|
123
|
+
* the Amodal cloud need zero config; the cloud's deploy pipeline injects
|
|
124
|
+
* the JWKS URL via the `AMODAL_JWKS_URL` env var. Self-hosters override
|
|
125
|
+
* via the optional `jwksUrl` field.
|
|
126
|
+
*/
|
|
127
|
+
declare const AmodalAuthConfigSchema: z.ZodObject<{
|
|
128
|
+
type: z.ZodLiteral<"amodal">;
|
|
129
|
+
jwksUrl: z.ZodOptional<z.ZodString>;
|
|
130
|
+
issuer: z.ZodOptional<z.ZodString>;
|
|
131
|
+
}, "strip", z.ZodTypeAny, {
|
|
132
|
+
type: "amodal";
|
|
133
|
+
issuer?: string | undefined;
|
|
134
|
+
jwksUrl?: string | undefined;
|
|
135
|
+
}, {
|
|
136
|
+
type: "amodal";
|
|
137
|
+
issuer?: string | undefined;
|
|
138
|
+
jwksUrl?: string | undefined;
|
|
139
|
+
}>;
|
|
140
|
+
export declare const AuthConfigSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
141
|
+
type: z.ZodLiteral<"none">;
|
|
142
|
+
/** Synthesized user id for the anonymous session. Defaults to `'anonymous'`. */
|
|
143
|
+
userId: z.ZodOptional<z.ZodString>;
|
|
144
|
+
}, "strip", z.ZodTypeAny, {
|
|
145
|
+
type: "none";
|
|
146
|
+
userId?: string | undefined;
|
|
147
|
+
}, {
|
|
148
|
+
type: "none";
|
|
149
|
+
userId?: string | undefined;
|
|
150
|
+
}>, z.ZodObject<{
|
|
151
|
+
type: z.ZodLiteral<"jwt_secret">;
|
|
152
|
+
/** Shared HMAC secret used to verify incoming JWTs. */
|
|
153
|
+
secret: z.ZodString;
|
|
154
|
+
/** HMAC algorithm. Defaults to HS256. */
|
|
155
|
+
algorithm: z.ZodOptional<z.ZodEnum<["HS256", "HS384", "HS512"]>>;
|
|
156
|
+
/** Expected `iss` claim. Optional. */
|
|
157
|
+
issuer: z.ZodOptional<z.ZodString>;
|
|
158
|
+
/** Expected `aud` claim. Optional. */
|
|
159
|
+
audience: z.ZodOptional<z.ZodString>;
|
|
160
|
+
}, "strip", z.ZodTypeAny, {
|
|
161
|
+
type: "jwt_secret";
|
|
162
|
+
secret: string;
|
|
163
|
+
issuer?: string | undefined;
|
|
164
|
+
audience?: string | undefined;
|
|
165
|
+
algorithm?: "HS256" | "HS384" | "HS512" | undefined;
|
|
166
|
+
}, {
|
|
167
|
+
type: "jwt_secret";
|
|
168
|
+
secret: string;
|
|
169
|
+
issuer?: string | undefined;
|
|
170
|
+
audience?: string | undefined;
|
|
171
|
+
algorithm?: "HS256" | "HS384" | "HS512" | undefined;
|
|
172
|
+
}>, z.ZodObject<{
|
|
173
|
+
type: z.ZodLiteral<"oidc">;
|
|
174
|
+
/** OIDC issuer URL — the IdP's discovery base (`https://acme.okta.com`). */
|
|
175
|
+
issuer: z.ZodString;
|
|
176
|
+
clientId: z.ZodString;
|
|
177
|
+
clientSecret: z.ZodString;
|
|
178
|
+
/** Where the IdP redirects back after login. Must be registered with the IdP. */
|
|
179
|
+
callbackUrl: z.ZodString;
|
|
180
|
+
/** OAuth scopes to request. Defaults to `['openid', 'email', 'profile']`. */
|
|
181
|
+
scopes: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
182
|
+
/**
|
|
183
|
+
* HMAC secret used to sign the session JWT stored in the runtime's cookie.
|
|
184
|
+
* Distinct from the IdP — this is purely the runtime's session signing key.
|
|
185
|
+
*/
|
|
186
|
+
sessionSecret: z.ZodString;
|
|
187
|
+
/** Cookie name for the session JWT. Defaults to `'amodal_session'`. */
|
|
188
|
+
cookieName: z.ZodOptional<z.ZodString>;
|
|
189
|
+
/** Session TTL in seconds. Defaults to 24h. */
|
|
190
|
+
sessionTtlSeconds: z.ZodOptional<z.ZodNumber>;
|
|
191
|
+
}, "strip", z.ZodTypeAny, {
|
|
192
|
+
type: "oidc";
|
|
193
|
+
issuer: string;
|
|
194
|
+
clientId: string;
|
|
195
|
+
clientSecret: string;
|
|
196
|
+
callbackUrl: string;
|
|
197
|
+
sessionSecret: string;
|
|
198
|
+
scopes?: string[] | undefined;
|
|
199
|
+
cookieName?: string | undefined;
|
|
200
|
+
sessionTtlSeconds?: number | undefined;
|
|
201
|
+
}, {
|
|
202
|
+
type: "oidc";
|
|
203
|
+
issuer: string;
|
|
204
|
+
clientId: string;
|
|
205
|
+
clientSecret: string;
|
|
206
|
+
callbackUrl: string;
|
|
207
|
+
sessionSecret: string;
|
|
208
|
+
scopes?: string[] | undefined;
|
|
209
|
+
cookieName?: string | undefined;
|
|
210
|
+
sessionTtlSeconds?: number | undefined;
|
|
211
|
+
}>, z.ZodObject<{
|
|
212
|
+
type: z.ZodLiteral<"header">;
|
|
213
|
+
headerName: z.ZodOptional<z.ZodString>;
|
|
214
|
+
}, "strip", z.ZodTypeAny, {
|
|
215
|
+
type: "header";
|
|
216
|
+
headerName?: string | undefined;
|
|
217
|
+
}, {
|
|
218
|
+
type: "header";
|
|
219
|
+
headerName?: string | undefined;
|
|
220
|
+
}>, z.ZodObject<{
|
|
221
|
+
type: z.ZodLiteral<"custom">;
|
|
222
|
+
/**
|
|
223
|
+
* Module path (relative to the agent's runtime directory) whose default
|
|
224
|
+
* export implements the `AuthStrategy` interface. The runtime imports
|
|
225
|
+
* this file at startup and validates the shape.
|
|
226
|
+
*/
|
|
227
|
+
module: z.ZodString;
|
|
228
|
+
}, "strip", z.ZodTypeAny, {
|
|
229
|
+
type: "custom";
|
|
230
|
+
module: string;
|
|
231
|
+
}, {
|
|
232
|
+
type: "custom";
|
|
233
|
+
module: string;
|
|
234
|
+
}>, z.ZodObject<{
|
|
235
|
+
type: z.ZodLiteral<"amodal">;
|
|
236
|
+
jwksUrl: z.ZodOptional<z.ZodString>;
|
|
237
|
+
issuer: z.ZodOptional<z.ZodString>;
|
|
238
|
+
}, "strip", z.ZodTypeAny, {
|
|
239
|
+
type: "amodal";
|
|
240
|
+
issuer?: string | undefined;
|
|
241
|
+
jwksUrl?: string | undefined;
|
|
242
|
+
}, {
|
|
243
|
+
type: "amodal";
|
|
244
|
+
issuer?: string | undefined;
|
|
245
|
+
jwksUrl?: string | undefined;
|
|
246
|
+
}>]>;
|
|
247
|
+
export type AuthConfig = z.infer<typeof AuthConfigSchema>;
|
|
248
|
+
export type NoneAuthConfig = z.infer<typeof NoneAuthConfigSchema>;
|
|
249
|
+
export type JwtSecretAuthConfig = z.infer<typeof JwtSecretAuthConfigSchema>;
|
|
250
|
+
export type OidcAuthConfig = z.infer<typeof OidcAuthConfigSchema>;
|
|
251
|
+
export type HeaderAuthConfig = z.infer<typeof HeaderAuthConfigSchema>;
|
|
252
|
+
export type CustomAuthConfig = z.infer<typeof CustomAuthConfigSchema>;
|
|
253
|
+
export type AmodalAuthConfig = z.infer<typeof AmodalAuthConfigSchema>;
|
|
254
|
+
/**
|
|
255
|
+
* Parse + validate an `auth` block from agent config. Throws a clear
|
|
256
|
+
* error on any malformed shape so misconfiguration fails at startup
|
|
257
|
+
* rather than at first request. Pass `undefined` / missing config to
|
|
258
|
+
* default to `{type: 'none'}`.
|
|
259
|
+
*/
|
|
260
|
+
export declare function parseAuthConfig(raw: unknown): AuthConfig;
|
|
261
|
+
export {};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Config-driven auth — discriminated union the agent owner sets in
|
|
8
|
+
* `amodal.json` (or whatever surfaces the runtime through). The host
|
|
9
|
+
* resolves any `env:` references against its secrets store before
|
|
10
|
+
* passing the config to `createAuthStrategy(config)`.
|
|
11
|
+
*
|
|
12
|
+
* {
|
|
13
|
+
* "auth": {
|
|
14
|
+
* "type": "oidc",
|
|
15
|
+
* "issuer": "https://acme.okta.com",
|
|
16
|
+
* ...
|
|
17
|
+
* }
|
|
18
|
+
* }
|
|
19
|
+
*/
|
|
20
|
+
import { z } from 'zod';
|
|
21
|
+
const NoneAuthConfigSchema = z.object({
|
|
22
|
+
type: z.literal('none'),
|
|
23
|
+
/** Synthesized user id for the anonymous session. Defaults to `'anonymous'`. */
|
|
24
|
+
userId: z.string().optional(),
|
|
25
|
+
});
|
|
26
|
+
const JwtSecretAuthConfigSchema = z.object({
|
|
27
|
+
type: z.literal('jwt_secret'),
|
|
28
|
+
/** Shared HMAC secret used to verify incoming JWTs. */
|
|
29
|
+
secret: z.string().min(1),
|
|
30
|
+
/** HMAC algorithm. Defaults to HS256. */
|
|
31
|
+
algorithm: z.enum(['HS256', 'HS384', 'HS512']).optional(),
|
|
32
|
+
/** Expected `iss` claim. Optional. */
|
|
33
|
+
issuer: z.string().optional(),
|
|
34
|
+
/** Expected `aud` claim. Optional. */
|
|
35
|
+
audience: z.string().optional(),
|
|
36
|
+
});
|
|
37
|
+
const OidcAuthConfigSchema = z.object({
|
|
38
|
+
type: z.literal('oidc'),
|
|
39
|
+
/** OIDC issuer URL — the IdP's discovery base (`https://acme.okta.com`). */
|
|
40
|
+
issuer: z.string().url(),
|
|
41
|
+
clientId: z.string().min(1),
|
|
42
|
+
clientSecret: z.string().min(1),
|
|
43
|
+
/** Where the IdP redirects back after login. Must be registered with the IdP. */
|
|
44
|
+
callbackUrl: z.string().url(),
|
|
45
|
+
/** OAuth scopes to request. Defaults to `['openid', 'email', 'profile']`. */
|
|
46
|
+
scopes: z.array(z.string()).optional(),
|
|
47
|
+
/**
|
|
48
|
+
* HMAC secret used to sign the session JWT stored in the runtime's cookie.
|
|
49
|
+
* Distinct from the IdP — this is purely the runtime's session signing key.
|
|
50
|
+
*/
|
|
51
|
+
sessionSecret: z.string().min(16),
|
|
52
|
+
/** Cookie name for the session JWT. Defaults to `'amodal_session'`. */
|
|
53
|
+
cookieName: z.string().optional(),
|
|
54
|
+
/** Session TTL in seconds. Defaults to 24h. */
|
|
55
|
+
sessionTtlSeconds: z.number().int().positive().optional(),
|
|
56
|
+
});
|
|
57
|
+
const HeaderAuthConfigSchema = z.object({
|
|
58
|
+
type: z.literal('header'),
|
|
59
|
+
headerName: z.string().optional(),
|
|
60
|
+
});
|
|
61
|
+
const CustomAuthConfigSchema = z.object({
|
|
62
|
+
type: z.literal('custom'),
|
|
63
|
+
/**
|
|
64
|
+
* Module path (relative to the agent's runtime directory) whose default
|
|
65
|
+
* export implements the `AuthStrategy` interface. The runtime imports
|
|
66
|
+
* this file at startup and validates the shape.
|
|
67
|
+
*/
|
|
68
|
+
module: z.string().min(1),
|
|
69
|
+
});
|
|
70
|
+
/**
|
|
71
|
+
* "Sign in with Amodal" — verifies platform JWTs minted by the Amodal
|
|
72
|
+
* cloud (or any self-hosted Amodal-equivalent platform). Agent owners on
|
|
73
|
+
* the Amodal cloud need zero config; the cloud's deploy pipeline injects
|
|
74
|
+
* the JWKS URL via the `AMODAL_JWKS_URL` env var. Self-hosters override
|
|
75
|
+
* via the optional `jwksUrl` field.
|
|
76
|
+
*/
|
|
77
|
+
const AmodalAuthConfigSchema = z.object({
|
|
78
|
+
type: z.literal('amodal'),
|
|
79
|
+
jwksUrl: z.string().url().optional(),
|
|
80
|
+
issuer: z.string().optional(),
|
|
81
|
+
});
|
|
82
|
+
export const AuthConfigSchema = z.discriminatedUnion('type', [
|
|
83
|
+
NoneAuthConfigSchema,
|
|
84
|
+
JwtSecretAuthConfigSchema,
|
|
85
|
+
OidcAuthConfigSchema,
|
|
86
|
+
HeaderAuthConfigSchema,
|
|
87
|
+
CustomAuthConfigSchema,
|
|
88
|
+
AmodalAuthConfigSchema,
|
|
89
|
+
]);
|
|
90
|
+
/**
|
|
91
|
+
* Parse + validate an `auth` block from agent config. Throws a clear
|
|
92
|
+
* error on any malformed shape so misconfiguration fails at startup
|
|
93
|
+
* rather than at first request. Pass `undefined` / missing config to
|
|
94
|
+
* default to `{type: 'none'}`.
|
|
95
|
+
*/
|
|
96
|
+
export function parseAuthConfig(raw) {
|
|
97
|
+
if (raw == null)
|
|
98
|
+
return { type: 'none' };
|
|
99
|
+
const parsed = AuthConfigSchema.safeParse(raw);
|
|
100
|
+
if (!parsed.success) {
|
|
101
|
+
throw new Error(`Invalid auth config: ${parsed.error.errors
|
|
102
|
+
.map((e) => `${e.path.join('.') || '<root>'}: ${e.message}`)
|
|
103
|
+
.join('; ')}`);
|
|
104
|
+
}
|
|
105
|
+
return parsed.data;
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/auth/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect } from 'vitest';
|
|
7
|
+
import { parseAuthConfig } from './config.js';
|
|
8
|
+
describe('parseAuthConfig', () => {
|
|
9
|
+
it('defaults to {type: none} when undefined', () => {
|
|
10
|
+
expect(parseAuthConfig(undefined)).toEqual({ type: 'none' });
|
|
11
|
+
expect(parseAuthConfig(null)).toEqual({ type: 'none' });
|
|
12
|
+
});
|
|
13
|
+
it('accepts a valid none config', () => {
|
|
14
|
+
expect(parseAuthConfig({ type: 'none' })).toEqual({ type: 'none' });
|
|
15
|
+
expect(parseAuthConfig({ type: 'none', userId: 'guest' })).toEqual({
|
|
16
|
+
type: 'none',
|
|
17
|
+
userId: 'guest',
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
it('accepts a valid jwt_secret config', () => {
|
|
21
|
+
const cfg = parseAuthConfig({ type: 'jwt_secret', secret: 'sssh' });
|
|
22
|
+
expect(cfg.type).toBe('jwt_secret');
|
|
23
|
+
});
|
|
24
|
+
it('rejects jwt_secret without secret', () => {
|
|
25
|
+
expect(() => parseAuthConfig({ type: 'jwt_secret' })).toThrow(/secret/);
|
|
26
|
+
});
|
|
27
|
+
it('accepts a valid oidc config', () => {
|
|
28
|
+
const cfg = parseAuthConfig({
|
|
29
|
+
type: 'oidc',
|
|
30
|
+
issuer: 'https://acme.okta.com',
|
|
31
|
+
clientId: 'abc',
|
|
32
|
+
clientSecret: 'shh',
|
|
33
|
+
callbackUrl: 'https://agent.example.com/auth/callback',
|
|
34
|
+
sessionSecret: 'a-secret-of-at-least-16-chars-long',
|
|
35
|
+
});
|
|
36
|
+
expect(cfg.type).toBe('oidc');
|
|
37
|
+
});
|
|
38
|
+
it('rejects oidc with a non-URL issuer', () => {
|
|
39
|
+
expect(() => parseAuthConfig({
|
|
40
|
+
type: 'oidc',
|
|
41
|
+
issuer: 'not-a-url',
|
|
42
|
+
clientId: 'a',
|
|
43
|
+
clientSecret: 'b',
|
|
44
|
+
callbackUrl: 'https://x.test/cb',
|
|
45
|
+
sessionSecret: 'a-secret-of-at-least-16-chars-long',
|
|
46
|
+
})).toThrow(/url/i);
|
|
47
|
+
});
|
|
48
|
+
it('rejects oidc with too-short sessionSecret', () => {
|
|
49
|
+
expect(() => parseAuthConfig({
|
|
50
|
+
type: 'oidc',
|
|
51
|
+
issuer: 'https://x.test',
|
|
52
|
+
clientId: 'a',
|
|
53
|
+
clientSecret: 'b',
|
|
54
|
+
callbackUrl: 'https://x.test/cb',
|
|
55
|
+
sessionSecret: 'short',
|
|
56
|
+
})).toThrow(/sessionSecret/);
|
|
57
|
+
});
|
|
58
|
+
it('accepts custom config with module path', () => {
|
|
59
|
+
expect(parseAuthConfig({ type: 'custom', module: './my-auth.ts' })).toEqual({
|
|
60
|
+
type: 'custom',
|
|
61
|
+
module: './my-auth.ts',
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
it('accepts a bare amodal config (zero-config sign-in with Amodal)', () => {
|
|
65
|
+
expect(parseAuthConfig({ type: 'amodal' })).toEqual({ type: 'amodal' });
|
|
66
|
+
});
|
|
67
|
+
it('accepts amodal config with optional jwksUrl + issuer overrides', () => {
|
|
68
|
+
expect(parseAuthConfig({
|
|
69
|
+
type: 'amodal',
|
|
70
|
+
jwksUrl: 'https://example.com/.well-known/jwks.json',
|
|
71
|
+
issuer: 'custom-issuer',
|
|
72
|
+
})).toEqual({
|
|
73
|
+
type: 'amodal',
|
|
74
|
+
jwksUrl: 'https://example.com/.well-known/jwks.json',
|
|
75
|
+
issuer: 'custom-issuer',
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
it('rejects amodal config with a non-URL jwksUrl', () => {
|
|
79
|
+
expect(() => parseAuthConfig({ type: 'amodal', jwksUrl: 'not-a-url' })).toThrow(/url/i);
|
|
80
|
+
});
|
|
81
|
+
it('rejects unknown type', () => {
|
|
82
|
+
expect(() => parseAuthConfig({ type: 'wat', whatever: true })).toThrow(/Invalid auth config/);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
//# sourceMappingURL=config.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.test.js","sourceRoot":"","sources":["../../../src/auth/config.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Translate a parsed `AuthConfig` into an `AuthStrategy` instance.
|
|
8
|
+
* The host (cloud's runtime, self-hoster's app) calls this once at boot
|
|
9
|
+
* with the agent's already-resolved config.
|
|
10
|
+
*/
|
|
11
|
+
import type { AuthConfig } from './config.js';
|
|
12
|
+
import type { AuthStrategy } from './types.js';
|
|
13
|
+
/**
|
|
14
|
+
* Build an `AuthStrategy` from a validated `AuthConfig`. For `'custom'`
|
|
15
|
+
* type configs this is async (the user's module is dynamically imported);
|
|
16
|
+
* everything else resolves synchronously but the function is uniformly
|
|
17
|
+
* async for ergonomics.
|
|
18
|
+
*/
|
|
19
|
+
export declare function createAuthStrategy(config: AuthConfig): Promise<AuthStrategy>;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import { NoneAuthStrategy } from './strategies/none.js';
|
|
7
|
+
import { HeaderAuthStrategy } from './strategies/header.js';
|
|
8
|
+
import { JwtSecretAuthStrategy } from './strategies/jwt-secret.js';
|
|
9
|
+
import { OidcAuthStrategy } from './strategies/oidc.js';
|
|
10
|
+
import { AmodalAuthStrategy } from './strategies/amodal.js';
|
|
11
|
+
import { loadCustomStrategy } from './strategies/custom-loader.js';
|
|
12
|
+
/**
|
|
13
|
+
* Build an `AuthStrategy` from a validated `AuthConfig`. For `'custom'`
|
|
14
|
+
* type configs this is async (the user's module is dynamically imported);
|
|
15
|
+
* everything else resolves synchronously but the function is uniformly
|
|
16
|
+
* async for ergonomics.
|
|
17
|
+
*/
|
|
18
|
+
export async function createAuthStrategy(config) {
|
|
19
|
+
switch (config.type) {
|
|
20
|
+
case 'none':
|
|
21
|
+
return new NoneAuthStrategy(config.userId !== undefined ? { userId: config.userId } : {});
|
|
22
|
+
case 'header':
|
|
23
|
+
return new HeaderAuthStrategy(config.headerName !== undefined ? { headerName: config.headerName } : {});
|
|
24
|
+
case 'jwt_secret':
|
|
25
|
+
return new JwtSecretAuthStrategy({
|
|
26
|
+
secret: config.secret,
|
|
27
|
+
...(config.algorithm ? { algorithm: config.algorithm } : {}),
|
|
28
|
+
...(config.issuer ? { issuer: config.issuer } : {}),
|
|
29
|
+
...(config.audience ? { audience: config.audience } : {}),
|
|
30
|
+
});
|
|
31
|
+
case 'oidc':
|
|
32
|
+
return new OidcAuthStrategy({
|
|
33
|
+
issuer: config.issuer,
|
|
34
|
+
clientId: config.clientId,
|
|
35
|
+
clientSecret: config.clientSecret,
|
|
36
|
+
callbackUrl: config.callbackUrl,
|
|
37
|
+
...(config.scopes ? { scopes: config.scopes } : {}),
|
|
38
|
+
sessionSecret: config.sessionSecret,
|
|
39
|
+
...(config.cookieName ? { cookieName: config.cookieName } : {}),
|
|
40
|
+
...(config.sessionTtlSeconds
|
|
41
|
+
? { sessionTtlSeconds: config.sessionTtlSeconds }
|
|
42
|
+
: {}),
|
|
43
|
+
});
|
|
44
|
+
case 'custom':
|
|
45
|
+
return loadCustomStrategy(config.module);
|
|
46
|
+
case 'amodal':
|
|
47
|
+
return new AmodalAuthStrategy({
|
|
48
|
+
...(config.jwksUrl ? { jwksUrl: config.jwksUrl } : {}),
|
|
49
|
+
...(config.issuer ? { issuer: config.issuer } : {}),
|
|
50
|
+
});
|
|
51
|
+
default: {
|
|
52
|
+
const _exhaustive = config;
|
|
53
|
+
throw new Error(`Unknown auth config type: ${JSON.stringify(_exhaustive)}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../../../src/auth/factory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
7
|
+
import { createAuthStrategy } from './factory.js';
|
|
8
|
+
vi.mock('openid-client', () => ({
|
|
9
|
+
// OidcAuthStrategy doesn't call discovery() at construction — it
|
|
10
|
+
// lazy-init's on first request. The factory only needs the module
|
|
11
|
+
// to import cleanly.
|
|
12
|
+
discovery: vi.fn(),
|
|
13
|
+
randomPKCECodeVerifier: vi.fn(),
|
|
14
|
+
calculatePKCECodeChallenge: vi.fn(),
|
|
15
|
+
randomState: vi.fn(),
|
|
16
|
+
buildAuthorizationUrl: vi.fn(),
|
|
17
|
+
authorizationCodeGrant: vi.fn(),
|
|
18
|
+
}));
|
|
19
|
+
describe('createAuthStrategy', () => {
|
|
20
|
+
it('returns NoneAuthStrategy for type: none', async () => {
|
|
21
|
+
const s = await createAuthStrategy({ type: 'none' });
|
|
22
|
+
expect(s.name).toBe('none');
|
|
23
|
+
});
|
|
24
|
+
it('returns HeaderAuthStrategy for type: header', async () => {
|
|
25
|
+
const s = await createAuthStrategy({ type: 'header' });
|
|
26
|
+
expect(s.name).toBe('header');
|
|
27
|
+
});
|
|
28
|
+
it('returns JwtSecretAuthStrategy for type: jwt_secret', async () => {
|
|
29
|
+
const s = await createAuthStrategy({ type: 'jwt_secret', secret: 'shh' });
|
|
30
|
+
expect(s.name).toBe('jwt-secret');
|
|
31
|
+
});
|
|
32
|
+
it('returns OidcAuthStrategy for type: oidc', async () => {
|
|
33
|
+
const s = await createAuthStrategy({
|
|
34
|
+
type: 'oidc',
|
|
35
|
+
issuer: 'https://acme.okta.com',
|
|
36
|
+
clientId: 'abc',
|
|
37
|
+
clientSecret: 'shh',
|
|
38
|
+
callbackUrl: 'https://agent.example.com/auth/callback',
|
|
39
|
+
sessionSecret: 'a-secret-of-at-least-16-chars-long',
|
|
40
|
+
});
|
|
41
|
+
expect(s.name).toBe('oidc');
|
|
42
|
+
expect(s.routes).toBeDefined();
|
|
43
|
+
});
|
|
44
|
+
it('returns AmodalAuthStrategy for type: amodal', async () => {
|
|
45
|
+
const s = await createAuthStrategy({ type: 'amodal' });
|
|
46
|
+
expect(s.name).toBe('amodal');
|
|
47
|
+
});
|
|
48
|
+
it('passes overrides through to AmodalAuthStrategy', async () => {
|
|
49
|
+
const s = await createAuthStrategy({
|
|
50
|
+
type: 'amodal',
|
|
51
|
+
jwksUrl: 'https://example.com/.well-known/jwks.json',
|
|
52
|
+
issuer: 'custom-issuer',
|
|
53
|
+
});
|
|
54
|
+
expect(s.name).toBe('amodal');
|
|
55
|
+
});
|
|
56
|
+
it('throws when custom module fails to load', async () => {
|
|
57
|
+
await expect(createAuthStrategy({ type: 'custom', module: '/nonexistent/path.ts' })).rejects.toThrow(/Failed to load custom auth strategy/);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
//# sourceMappingURL=factory.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.test.js","sourceRoot":"","sources":["../../../src/auth/factory.test.ts"],"names":[],"mappings":"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"}
|