@amodalai/amodal 0.3.70 → 0.3.72

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/CHANGELOG.md CHANGED
@@ -1,5 +1,195 @@
1
1
  # @amodalai/amodal
2
2
 
3
+ ## 0.3.72
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [36837dd]
8
+ - Updated dependencies [158c851]
9
+ - @amodalai/studio@0.3.72
10
+ - @amodalai/core@0.3.72
11
+ - @amodalai/db@0.3.72
12
+ - @amodalai/runtime@0.3.72
13
+ - @amodalai/types@0.3.72
14
+ - @amodalai/runtime-app@0.3.72
15
+
16
+ ## 0.3.71
17
+
18
+ ### Patch Changes
19
+
20
+ - bde01f0: Add config-driven auth on top of the `feat/auth-controller` Warden
21
+ primitive. Agent owners describe their auth in `amodal.json`; the
22
+ runtime parses, validates, and instantiates the right `AuthStrategy`
23
+ at boot.
24
+
25
+ ```json
26
+ {
27
+ "auth": {
28
+ "type": "oidc",
29
+ "issuer": "https://acme.okta.com",
30
+ "clientId": "abc123",
31
+ "clientSecret": "env:OKTA_CLIENT_SECRET",
32
+ "callbackUrl": "https://hr-helper.acme.com/auth/callback",
33
+ "sessionSecret": "env:SESSION_SIGNING_SECRET"
34
+ }
35
+ }
36
+ ```
37
+
38
+ ```ts
39
+ import {
40
+ parseAuthConfig,
41
+ createAuthStrategy,
42
+ JwksAuthStrategy,
43
+ authenticate,
44
+ authRouter,
45
+ } from "@amodalai/runtime";
46
+
47
+ const userAuth = await createAuthStrategy(parseAuthConfig(agentConfig.auth));
48
+ const studioJwt = new JwksAuthStrategy({ jwksUrl: process.env.JWKS_URL });
49
+
50
+ app.use("/api/files", authenticate(studioJwt)); // Studio only
51
+ app.use("/chat", authenticate(studioJwt, userAuth)); // either
52
+ app.use(authRouter(userAuth)); // OAuth callbacks
53
+ ```
54
+
55
+ **Five `auth.type` modes** covering the persona spectrum:
56
+ - `none` — synthesized anonymous identity (public chatbots / dev)
57
+ - `jwt_secret` — HMAC-verify JWTs minted by another server (ISV / server-mediated)
58
+ - `oidc` — full OAuth2.1/OIDC dance via `openid-client` (Okta, Azure AD, Google Workspace, Auth0 OIDC, Keycloak — anything OIDC-compliant). Handles login redirect, PKCE+state, callback exchange, signed-cookie sessions, JWKS verification.
59
+ - `header` — trusted upstream `X-Auth-User` (proxied auth)
60
+ - `custom` — `{module: './my-auth.ts'}` dynamically imports a user-supplied strategy class. The escape hatch for Auth0 SDK / Supabase `getUser` / any auth system that doesn't fit the four modes above.
61
+
62
+ **Validation**: `parseAuthConfig(raw)` (zod-backed) gives clear errors on
63
+ malformed configs at startup, not at first request.
64
+
65
+ **`OidcAuthStrategy`** is the meaty piece — ~270 LOC implementing the
66
+ OAuth dance via `openid-client` v6 (Web-standards), session signing via
67
+ HMAC, encrypted state cookie for the redirect round-trip. Self-contained;
68
+ no database needed; survives multi-instance fleets.
69
+
70
+ Adds `openid-client` as a runtime dependency.
71
+
72
+ This PR delivers the config-facing surface that makes the Warden
73
+ primitive useful to non-developers — agent owners edit JSON (or, in
74
+ follow-up PRs, a Studio UI / `amodal auth init` CLI), the runtime
75
+ wires up auth from there.
76
+
77
+ - bde01f0: Add a Warden-shape pluggable auth primitive: `authenticate(...strategies)`
78
+ returns Express middleware that runs the strategies in order, picks the
79
+ first that applies and authenticates, and attaches a canonical
80
+ `AuthSession` to `res.locals.session` (or 401s the request). Single-winner
81
+ chain — no merging across strategies, no implicit identity overrides.
82
+
83
+ Each strategy implements two methods (modeled on Rails' Warden):
84
+ - `valid(req): boolean` — cheap synchronous check, "does this strategy
85
+ apply at all?". Strategies that return false are skipped without
86
+ paying the `authenticate` cost.
87
+ - `authenticate(req): Promise<AuthResult>` — slow path. Returns a
88
+ discriminated union `{kind: 'authenticated', session}` or
89
+ `{kind: 'rejected', reason}`. No exceptions for control flow — plugin
90
+ authors can't accidentally bypass auth by throwing the wrong sentinel.
91
+
92
+ Per-route mounting solves the route-bifurcation problem cleanly:
93
+
94
+ ```ts
95
+ const platformJwt = new JwksAuthStrategy({jwksUrl});
96
+ const endUser = new OidcStrategy({...}); // user-supplied or built-in
97
+
98
+ // Studio routes — only platform JWT is in the chain
99
+ app.use('/api/files', authenticate(platformJwt));
100
+
101
+ // Chat routes — accept platform JWT (Studio test chat) OR end-user auth
102
+ app.use('/chat', authenticate(platformJwt, endUser));
103
+
104
+ // Login-flow routes registered by strategies that need them
105
+ app.use(authRouter(endUser));
106
+ ```
107
+
108
+ A request hitting `/api/files` with an end-user token can't be
109
+ authenticated by accident — `endUser` isn't in that chain.
110
+
111
+ Ships five built-in strategies covering the common amodal personas:
112
+ - **`JwksAuthStrategy`** — Bearer JWT verified against a remote JWKS.
113
+ Pass-through to `jose.createRemoteJWKSet` options for ops visibility
114
+ into key rotation.
115
+ - **`ApiKeyAuthStrategy`** — `ak_*` Bearer tokens validated via a
116
+ caller-supplied callback. LRU-cached (configurable cap, default 10k
117
+ entries) so repeated requests skip the round-trip.
118
+ - **`HeaderAuthStrategy`** — trusted upstream header (default
119
+ `X-Auth-User`) for service-to-service / proxied auth.
120
+ - **`NoneAuthStrategy`** — synthesizes an anonymous session. Place last
121
+ in the chain for public agents / dev environments.
122
+ - **`CookieSessionStrategy`** — session JWT in a cookie (default
123
+ `amodal_session`), verified against JWKS. For SPA + runtime stacks
124
+ that don't sit behind a Bearer-injecting edge proxy.
125
+
126
+ Adds `jose` and `lru-cache` as runtime dependencies.
127
+
128
+ The `AuthSession` shape is canonical across all strategies: `{user: {id,
129
+ email?, name?}, method, agentId?, scopeId?, claims?}`. No `token` field
130
+ on the surface (avoids credential leaks via accidental log serialization);
131
+ strategies expose raw provider claims under `claims` for callers that
132
+ need them.
133
+
134
+ Per-mount `logger` option emits a structured `AuthLogEvent` per request
135
+ (`{strategy, outcome, durationMs, reason?}`) for observability.
136
+
137
+ External identity providers (Auth0, Supabase, custom OIDC, SAML) are
138
+ expected to ship as separate strategy classes — either inside an
139
+ agent's runtime code or as third-party packages — implementing the
140
+ `AuthStrategy` interface. No first-party provider packages in this PR;
141
+ the primitive layer is the contract.
142
+
143
+ - bde01f0: Add a Studio "Authentication" tab for editing the agent's `auth` block
144
+ in `amodal.json` form-style. Builds on the config-driven layer from the
145
+ `feat/auth-config` PR.
146
+
147
+ Agent owners pick the auth type from a card grid (Sign in with Amodal /
148
+ Public / Shared JWT secret / OIDC / Trusted header / Custom) and fill
149
+ in type-specific fields. Saves a draft through the existing
150
+ workspace-edit pipeline; the user commits via "Publish changes" to land
151
+ it on disk.
152
+
153
+ "Sign in with Amodal" is the zero-config option: visitors sign in with
154
+ their existing Amodal account, the runtime verifies the platform JWT
155
+ against Amodal's JWKS, no client setup or secrets required. Backed by a
156
+ new `AmodalAuthStrategy` (a thin `JwksAuthStrategy` wrapper preconfigured
157
+ with the Amodal cloud JWKS URL + issuer; both overridable for self-hosted
158
+ Amodal-equivalent platforms).
159
+
160
+ Implementation mirrors the `embed-config` pattern:
161
+ - `lib/auth-config.ts` — Studio-side editable draft shape +
162
+ read/write helpers for the `auth` block in `amodal.json`. Serializes
163
+ the draft back to the runtime's strict `AuthConfig` discriminated
164
+ union shape on save.
165
+ - `server/routes/auth-config.ts` — `GET/PUT /api/auth-config`,
166
+ same shape as `embed-config` (drafts, capability check, etc.).
167
+ Server-side validation rejects obvious problems before the file
168
+ lands on disk.
169
+ - `hooks/useAuthConfig.ts` — fetch + save hook for the page.
170
+ - `pages/AuthPage.tsx` — the form. Includes a `SecretField` atom that
171
+ highlights `env:` references and masks plain secret values, so
172
+ agent owners are nudged toward the right pattern.
173
+ - Wired into `router.tsx` + `StudioShell` config nav.
174
+
175
+ Secret fields default to `env:` reference values so secrets land in
176
+ the agent's secrets table (encrypted), not in `amodal.json` (in git).
177
+
178
+ The form covers every persona walked through in the auth design:
179
+ Public chatbots → `none`. ISV server-mediated → `jwt_secret`.
180
+ Internal ops SSO → `oidc` (login dance handled by the runtime).
181
+ Proxied auth → `header`. Anything else → `custom` module path.
182
+
183
+ - Updated dependencies [bde01f0]
184
+ - Updated dependencies [bde01f0]
185
+ - Updated dependencies [bde01f0]
186
+ - @amodalai/runtime@0.3.71
187
+ - @amodalai/core@0.3.71
188
+ - @amodalai/studio@0.3.71
189
+ - @amodalai/runtime-app@0.3.71
190
+ - @amodalai/types@0.3.71
191
+ - @amodalai/db@0.3.71
192
+
3
193
  ## 0.3.70
4
194
 
5
195
  ### Patch Changes