@semiont/backend 0.5.7 → 0.5.9

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/index.js CHANGED
@@ -12,7 +12,6 @@ import { SemiontProject, loadEnvironmentConfig } from '@semiont/core/node';
12
12
  import { exportBackup, importBackup, readEntityTypesProjection, exportLinkedData, importLinkedData, startMakeMeaning, ResourceOperations, ResourceContext } from '@semiont/make-meaning';
13
13
  import { PrismaClient } from '@prisma/client';
14
14
  import { PrismaPg } from '@prisma/adapter-pg';
15
- import { setCookie, deleteCookie, getCookie } from 'hono/cookie';
16
15
  import { HTTPException } from 'hono/http-exception';
17
16
  import Ajv from 'ajv';
18
17
  import addFormats from 'ajv-formats';
@@ -30,11 +29,20 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
30
29
  var __getOwnPropNames = Object.getOwnPropertyNames;
31
30
  var __getProtoOf = Object.getPrototypeOf;
32
31
  var __hasOwnProp = Object.prototype.hasOwnProperty;
33
- var __esm = (fn, res) => function __init() {
34
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
32
+ var __esm = (fn, res, err) => function __init() {
33
+ if (err) throw err[0];
34
+ try {
35
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
36
+ } catch (e) {
37
+ throw err = [e], e;
38
+ }
35
39
  };
36
40
  var __commonJS = (cb, mod) => function __require() {
37
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
41
+ try {
42
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
43
+ } catch (e) {
44
+ throw mod = 0, e;
45
+ }
38
46
  };
39
47
  var __export = (target, all) => {
40
48
  for (var name in all)
@@ -186,6 +194,13 @@ var init_jwt_types = __esm({
186
194
  // `_userId` instead of recomputing `userToDid(user)`. Unset for human
187
195
  // tokens.
188
196
  agentDid: z.string().optional(),
197
+ // Per-user revocation epoch (SDK-AUTH-CORS Phase 2): every token carries the
198
+ // user's tokenVersion at mint; logout bumps User.tokenVersion, so a token
199
+ // whose tokenVersion is behind the user's current value is rejected.
200
+ // Required — a token minted before this feature lacks the claim and fails
201
+ // validation, so the holder re-authenticates. That is the intended
202
+ // revoke-every-session-on-rollout behavior, not a regression.
203
+ tokenVersion: z.number().int(),
189
204
  iat: z.number().optional(),
190
205
  exp: z.number().optional()
191
206
  });
@@ -12665,17 +12680,6 @@ var openapi_default = {
12665
12680
  }
12666
12681
  }
12667
12682
  },
12668
- MCPGenerateResponse: {
12669
- type: "object",
12670
- properties: {
12671
- refresh_token: {
12672
- type: "string"
12673
- }
12674
- },
12675
- required: [
12676
- "refresh_token"
12677
- ]
12678
- },
12679
12683
  Motivation: {
12680
12684
  type: "string",
12681
12685
  enum: [
@@ -16214,9 +16218,10 @@ var OAuthService = class {
16214
16218
  ...user.name && { name: user.name },
16215
16219
  domain: user.domain,
16216
16220
  provider: user.provider,
16217
- isAdmin: user.isAdmin
16221
+ isAdmin: user.isAdmin,
16222
+ tokenVersion: user.tokenVersion
16218
16223
  };
16219
- const token = accessToken(JWTService.generateToken(jwtPayload, "1h"));
16224
+ const token = accessToken(JWTService.generateToken(jwtPayload, "10m"));
16220
16225
  const refreshToken = JWTService.generateToken(jwtPayload, "30d");
16221
16226
  return { user, token, refreshToken, isNewUser };
16222
16227
  }
@@ -16240,6 +16245,9 @@ var OAuthService = class {
16240
16245
  if (!user || !user.isActive) {
16241
16246
  throw new Error("User not found or inactive");
16242
16247
  }
16248
+ if (payload.tokenVersion !== user.tokenVersion) {
16249
+ throw new Error("Token revoked");
16250
+ }
16243
16251
  return payload.agentDid ? { user, agentDid: payload.agentDid } : { user };
16244
16252
  }
16245
16253
  static async acceptTerms(userId2) {
@@ -16284,8 +16292,6 @@ var authMiddleware = async (c, next) => {
16284
16292
  let tokenStr;
16285
16293
  if (authHeader?.startsWith("Bearer ")) {
16286
16294
  tokenStr = authHeader.substring(7).trim();
16287
- } else {
16288
- tokenStr = getCookie(c, "semiont-token");
16289
16295
  }
16290
16296
  if (!tokenStr) {
16291
16297
  logger2.warn("Authentication failed: No token", {
@@ -16294,7 +16300,10 @@ var authMiddleware = async (c, next) => {
16294
16300
  path: c.req.path,
16295
16301
  method: c.req.method
16296
16302
  });
16297
- return c.json({ error: "Unauthorized" }, 401);
16303
+ return c.json({
16304
+ error: "Unauthorized",
16305
+ hint: "Authentication required: send an `Authorization: Bearer <token>` header. A raw browser navigation to a protected resource is unauthenticated."
16306
+ }, 401);
16298
16307
  }
16299
16308
  try {
16300
16309
  const { user, agentDid } = await OAuthService.getPrincipalFromToken(accessToken(tokenStr));
@@ -16464,22 +16473,15 @@ authRouter.post(
16464
16473
  ...user.name && { name: user.name },
16465
16474
  domain: user.domain,
16466
16475
  provider: user.provider,
16467
- isAdmin: user.isAdmin
16476
+ isAdmin: user.isAdmin,
16477
+ tokenVersion: user.tokenVersion
16468
16478
  };
16469
- const token = JWTService.generateToken(jwtPayload, "1h");
16479
+ const token = JWTService.generateToken(jwtPayload, "10m");
16470
16480
  const refreshToken = JWTService.generateToken(jwtPayload, "30d");
16471
16481
  await prisma2.user.update({
16472
16482
  where: { id: user.id },
16473
16483
  data: { lastLogin: /* @__PURE__ */ new Date() }
16474
16484
  });
16475
- setCookie(c, "semiont-token", token, {
16476
- httpOnly: true,
16477
- secure: process.env.NODE_ENV === "production",
16478
- sameSite: "Lax",
16479
- path: "/",
16480
- maxAge: 60 * 60
16481
- // 1 hour, matching access token lifetime
16482
- });
16483
16485
  const response = {
16484
16486
  success: true,
16485
16487
  user: {
@@ -16520,14 +16522,6 @@ authRouter.post(
16520
16522
  }
16521
16523
  const googleUser = await OAuthService.verifyGoogleToken(googleCredential(access_token));
16522
16524
  const { user, token, refreshToken, isNewUser } = await OAuthService.createOrUpdateUser(googleUser);
16523
- setCookie(c, "semiont-token", token, {
16524
- httpOnly: true,
16525
- secure: process.env.NODE_ENV === "production",
16526
- sameSite: "Lax",
16527
- path: "/",
16528
- maxAge: 60 * 60
16529
- // 1 hour, matching access token lifetime
16530
- });
16531
16525
  const response = {
16532
16526
  success: true,
16533
16527
  user: {
@@ -16579,15 +16573,19 @@ authRouter.post(
16579
16573
  if (!user || !user.isActive) {
16580
16574
  return c.json({ error: "User not found or inactive" }, 401);
16581
16575
  }
16576
+ if (payload.tokenVersion !== user.tokenVersion) {
16577
+ return c.json({ error: "Token revoked" }, 401);
16578
+ }
16582
16579
  const accessTokenPayload = {
16583
16580
  userId: userId(user.id),
16584
16581
  email: email(user.email),
16585
16582
  domain: user.domain,
16586
16583
  provider: user.provider,
16587
16584
  isAdmin: user.isAdmin,
16588
- ...user.name && { name: user.name }
16585
+ ...user.name && { name: user.name },
16586
+ tokenVersion: user.tokenVersion
16589
16587
  };
16590
- const accessToken2 = JWTService.generateToken(accessTokenPayload, "1h");
16588
+ const accessToken2 = JWTService.generateToken(accessTokenPayload, "10m");
16591
16589
  const response = {
16592
16590
  access_token: accessToken2
16593
16591
  };
@@ -16628,63 +16626,6 @@ authRouter.get("/api/users/me", authMiddleware, async (c) => {
16628
16626
  };
16629
16627
  return c.json(response, 200);
16630
16628
  });
16631
- authRouter.get("/api/tokens/mcp-setup", authMiddleware, async (c) => {
16632
- const callback = c.req.query("callback");
16633
- if (!callback) {
16634
- return c.json({ error: "Callback URL required" }, 400);
16635
- }
16636
- const allowedCallbackPatterns = [
16637
- /^http:\/\/localhost:\d+\/.*$/,
16638
- /^http:\/\/127\.0\.0\.1:\d+\/.*$/,
16639
- /^http:\/\/\[::1\]:\d+\/.*$/
16640
- ];
16641
- if (!allowedCallbackPatterns.some((p) => p.test(callback))) {
16642
- return c.json({ error: "Invalid callback URL. Must be a localhost URL for CLI authentication." }, 400);
16643
- }
16644
- const user = c.get("user");
16645
- try {
16646
- const tokenPayload = {
16647
- userId: userId(user.id),
16648
- email: email(user.email),
16649
- domain: user.domain,
16650
- provider: user.provider,
16651
- isAdmin: user.isAdmin,
16652
- ...user.name && { name: user.name }
16653
- };
16654
- const refreshToken = JWTService.generateToken(tokenPayload, "30d");
16655
- return c.redirect(`${callback}?token=${refreshToken}`, 302);
16656
- } catch (error) {
16657
- getRouteLogger2().error("MCP setup error", {
16658
- error: error instanceof Error ? error.message : String(error),
16659
- stack: error instanceof Error ? error.stack : void 0
16660
- });
16661
- return c.json({ error: "Failed to generate refresh token" }, 500);
16662
- }
16663
- });
16664
- authRouter.post("/api/tokens/mcp-generate", authMiddleware, async (c) => {
16665
- const user = c.get("user");
16666
- try {
16667
- const tokenPayload = {
16668
- userId: userId(user.id),
16669
- email: email(user.email),
16670
- domain: user.domain,
16671
- provider: user.provider,
16672
- isAdmin: user.isAdmin,
16673
- ...user.name && { name: user.name }
16674
- };
16675
- const refreshToken = JWTService.generateToken(tokenPayload, "30d");
16676
- const response = {
16677
- refresh_token: refreshToken
16678
- };
16679
- return c.json(response, 200);
16680
- } catch (error) {
16681
- getRouteLogger2().error("MCP token generation error", {
16682
- error: error instanceof Error ? error.message : String(error),
16683
- stack: error instanceof Error ? error.stack : void 0
16684
- });
16685
- return c.json({ error: "Failed to generate refresh token" }, 401);
16686
- }
16687
- });
16688
16629
  authRouter.post("/api/tokens/agent", async (c) => {
16689
16630
  const workerSecret = process.env.SEMIONT_WORKER_SECRET;
16690
16631
  if (!workerSecret) {
@@ -16739,7 +16680,8 @@ authRouter.post("/api/tokens/agent", async (c) => {
16739
16680
  domain: agentUser.domain,
16740
16681
  provider: agentUser.provider,
16741
16682
  isAdmin: false,
16742
- agentDid: did
16683
+ agentDid: did,
16684
+ tokenVersion: agentUser.tokenVersion
16743
16685
  }, "24h");
16744
16686
  return c.json({ token, did }, 200);
16745
16687
  });
@@ -16767,11 +16709,13 @@ authRouter.post("/api/users/accept-terms", authMiddleware, async (c) => {
16767
16709
  return c.json(response, 200);
16768
16710
  });
16769
16711
  authRouter.post("/api/users/logout", authMiddleware, async (c) => {
16770
- deleteCookie(c, "semiont-token", { path: "/" });
16771
- return c.json({
16772
- success: true,
16773
- message: "Logged out successfully"
16774
- }, 200);
16712
+ const user = c.get("user");
16713
+ const prisma2 = DatabaseConnection.getClient();
16714
+ await prisma2.user.update({
16715
+ where: { id: user.id },
16716
+ data: { tokenVersion: { increment: 1 } }
16717
+ });
16718
+ return c.body(null, 204);
16775
16719
  });
16776
16720
  authRouter.get("/api/cookies/consent", authMiddleware, async (c) => {
16777
16721
  return c.json({
@@ -17802,9 +17746,6 @@ var config = loadEnvironmentConfig(projectRoot, env);
17802
17746
  if (!config.services?.backend) {
17803
17747
  throw new Error("services.backend is required in environment config");
17804
17748
  }
17805
- if (!config.services.backend.corsOrigin) {
17806
- throw new Error("services.backend.corsOrigin is required in environment config");
17807
- }
17808
17749
  var backendService = config.services.backend;
17809
17750
  initializeLogger(config.logLevel);
17810
17751
  var logger = getLogger();
@@ -17835,10 +17776,7 @@ var makeMeaning = await startMakeMeaning(new SemiontProject(projectRoot), makeMe
17835
17776
  var __filename$1 = fileURLToPath(import.meta.url);
17836
17777
  var __dirname$1 = path.dirname(__filename$1);
17837
17778
  var app = new Hono();
17838
- app.use("*", cors({
17839
- origin: backendService.corsOrigin,
17840
- credentials: true
17841
- }));
17779
+ app.use("*", cors({ origin: "*" }));
17842
17780
  app.use("*", securityHeaders());
17843
17781
  app.use("*", requestIdMiddleware);
17844
17782
  app.use("*", errorLoggerMiddleware);
@@ -17926,6 +17864,11 @@ if (config.env?.NODE_ENV !== "test") {
17926
17864
  url: `http://localhost:${info.port}/api`,
17927
17865
  environment: config.env?.NODE_ENV ?? "development"
17928
17866
  });
17867
+ logger.info("Auth posture: bearer-only, open CORS", {
17868
+ cors: "any origin (*)",
17869
+ credentials: "disabled",
17870
+ auth: "Authorization: Bearer; media tokens via ?token= for /api/resources/:id"
17871
+ });
17929
17872
  try {
17930
17873
  const { JWTService: JWTService2 } = await Promise.resolve().then(() => (init_jwt(), jwt_exports));
17931
17874
  JWTService2.initialize(config);