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