@frontmcp/plugin-approval 1.8.5 → 1.8.6

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/README.md CHANGED
@@ -72,6 +72,24 @@ class DangerousTool extends ToolContext {
72
72
  }
73
73
  ```
74
74
 
75
+ A refused call reaches the client as an error result whose text is exactly the tool's `approvalMessage` and whose
76
+ `_meta.code` is `APPROVAL_REQUIRED`, in production too: the approval errors extend `PublicMcpError`.
77
+
78
+ A grant made through `this.approval` records the signed-in caller as its grantor, `userGrantor(<user id>)`
79
+ (`{ source: 'user', identifier, method: 'interactive' }`), or `{ source: 'user' }` when there is no signed-in user
80
+ (an anonymous `anon:` subject included). Pass `grantedBy` to record something else:
81
+
82
+ ```typescript
83
+ import { policyGrantor, userGrantor } from '@frontmcp/plugin-approval';
84
+
85
+ await this.approval.grantSessionApproval('ops:deploy', { grantedBy: policyGrantor('safe-list') });
86
+ await this.approval.grantUserApproval('ops:deploy', {
87
+ grantedBy: userGrantor('user-123', 'Jane Doe', { method: 'interactive' }),
88
+ });
89
+ ```
90
+
91
+ `revokeApproval()` records `revokedBy` by the same rule.
92
+
75
93
  ### Approval Scopes
76
94
 
77
95
  | Scope | Description |
@@ -1,17 +1,18 @@
1
1
  /**
2
2
  * Error classes for approval operations.
3
3
  *
4
- * These are standalone error classes that can be extended by plugins
5
- * for MCP-specific error handling.
4
+ * They are public MCP errors: a refusal is an answer for the caller, so its message reaches the
5
+ * client as written, in every environment, instead of being wrapped as an internal server error.
6
6
  *
7
- * @module @frontmcp/utils/approval
7
+ * @module @frontmcp/plugin-approval
8
8
  */
9
+ import { PublicMcpError } from '@frontmcp/sdk';
9
10
  import type { ApprovalScope } from './types';
10
11
  /**
11
12
  * Base class for approval-related errors.
12
13
  */
13
- export declare class ApprovalError extends Error {
14
- constructor(message: string);
14
+ export declare class ApprovalError extends PublicMcpError {
15
+ constructor(message: string, code?: string, statusCode?: number);
15
16
  }
16
17
  /**
17
18
  * Error thrown when tool approval is required but not granted.
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/approval/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C;;GAEG;AACH,qBAAa,aAAc,SAAQ,KAAK;gBAC1B,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,qBAAsB,SAAQ,aAAa;aAEpC,OAAO,EAAE;QACvB,sBAAsB;QACtB,MAAM,EAAE,MAAM,CAAC;QACf,6BAA6B;QAC7B,KAAK,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;QACxC,0BAA0B;QAC1B,OAAO,EAAE,MAAM,CAAC;QAChB,0CAA0C;QAC1C,eAAe,CAAC,EAAE;YAChB,aAAa,CAAC,EAAE,aAAa,EAAE,CAAC;YAChC,YAAY,CAAC,EAAE,aAAa,CAAC;YAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;YAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;YAClB,SAAS,CAAC,EAAE,MAAM,CAAC;SACpB,CAAC;KACH;gBAfe,OAAO,EAAE;QACvB,sBAAsB;QACtB,MAAM,EAAE,MAAM,CAAC;QACf,6BAA6B;QAC7B,KAAK,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;QACxC,0BAA0B;QAC1B,OAAO,EAAE,MAAM,CAAC;QAChB,0CAA0C;QAC1C,eAAe,CAAC,EAAE;YAChB,aAAa,CAAC,EAAE,aAAa,EAAE,CAAC;YAChC,YAAY,CAAC,EAAE,aAAa,CAAC;YAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;YAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;YAClB,SAAS,CAAC,EAAE,MAAM,CAAC;SACpB,CAAC;KACH;IAMH;;OAEG;IACH,cAAc;;;;;;;;gCAfQ,aAAa,EAAE;+BAChB,aAAa;2BACjB,MAAM;2BACN,MAAM;4BACL,MAAM;;;;CAuBzB;AAED;;GAEG;AACH,qBAAa,sBAAuB,SAAQ,aAAa;aAErC,SAAS,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO;aACvC,MAAM,EAAE,MAAM;gBADd,SAAS,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,EACvC,MAAM,EAAE,MAAM;IAMhC;;OAEG;IACH,cAAc;;;;;;;;CAUf;AAED;;GAEG;AACH,qBAAa,4BAA6B,SAAQ,aAAa;aAE3C,cAAc,EAAE,aAAa;aAC7B,aAAa,EAAE,aAAa,EAAE;gBAD9B,cAAc,EAAE,aAAa,EAC7B,aAAa,EAAE,aAAa,EAAE;IAShD;;OAEG;IACH,cAAc;;;;;;;;;CAWf;AAED;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,aAAa;aAEnC,MAAM,EAAE,MAAM;aACd,SAAS,EAAE,MAAM;gBADjB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM;IAMnC;;OAEG;IACH,cAAc;;;;;;;;;CAWf;AAED;;GAEG;AACH,qBAAa,wBAAyB,SAAQ,aAAa;aAEvC,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,cAAc;gBAA5D,MAAM,GAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,cAA0B,EACxF,OAAO,CAAC,EAAE,MAAM;IAMlB;;OAEG;IACH,cAAc;;;;;;;;CAUf"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/approval/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C;;GAEG;AACH,qBAAa,aAAc,SAAQ,cAAc;gBACnC,OAAO,EAAE,MAAM,EAAE,IAAI,SAAsB,EAAE,UAAU,SAAM;CAI1E;AAED;;GAEG;AACH,qBAAa,qBAAsB,SAAQ,aAAa;aAEpC,OAAO,EAAE;QACvB,sBAAsB;QACtB,MAAM,EAAE,MAAM,CAAC;QACf,6BAA6B;QAC7B,KAAK,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;QACxC,0BAA0B;QAC1B,OAAO,EAAE,MAAM,CAAC;QAChB,0CAA0C;QAC1C,eAAe,CAAC,EAAE;YAChB,aAAa,CAAC,EAAE,aAAa,EAAE,CAAC;YAChC,YAAY,CAAC,EAAE,aAAa,CAAC;YAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;YAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;YAClB,SAAS,CAAC,EAAE,MAAM,CAAC;SACpB,CAAC;KACH;gBAfe,OAAO,EAAE;QACvB,sBAAsB;QACtB,MAAM,EAAE,MAAM,CAAC;QACf,6BAA6B;QAC7B,KAAK,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;QACxC,0BAA0B;QAC1B,OAAO,EAAE,MAAM,CAAC;QAChB,0CAA0C;QAC1C,eAAe,CAAC,EAAE;YAChB,aAAa,CAAC,EAAE,aAAa,EAAE,CAAC;YAChC,YAAY,CAAC,EAAE,aAAa,CAAC;YAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;YAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;YAClB,SAAS,CAAC,EAAE,MAAM,CAAC;SACpB,CAAC;KACH;IAMH;;OAEG;IACH,cAAc;;;;;;;;gCAfQ,aAAa,EAAE;+BAChB,aAAa;2BACjB,MAAM;2BACN,MAAM;4BACL,MAAM;;;;CAuBzB;AAED;;GAEG;AACH,qBAAa,sBAAuB,SAAQ,aAAa;aAErC,SAAS,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO;aACvC,MAAM,EAAE,MAAM;gBADd,SAAS,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,EACvC,MAAM,EAAE,MAAM;IAMhC;;OAEG;IACH,cAAc;;;;;;;;CAUf;AAED;;GAEG;AACH,qBAAa,4BAA6B,SAAQ,aAAa;aAE3C,cAAc,EAAE,aAAa;aAC7B,aAAa,EAAE,aAAa,EAAE;gBAD9B,cAAc,EAAE,aAAa,EAC7B,aAAa,EAAE,aAAa,EAAE;IAWhD;;OAEG;IACH,cAAc;;;;;;;;;CAWf;AAED;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,aAAa;aAEnC,MAAM,EAAE,MAAM;aACd,SAAS,EAAE,MAAM;gBADjB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM;IAMnC;;OAEG;IACH,cAAc;;;;;;;;;CAWf;AAED;;GAEG;AACH,qBAAa,wBAAyB,SAAQ,aAAa;aAEvC,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,cAAc;gBAA5D,MAAM,GAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,cAA0B,EACxF,OAAO,CAAC,EAAE,MAAM;IAMlB;;OAEG;IACH,cAAc;;;;;;;;CAUf"}
package/esm/index.mjs CHANGED
@@ -27,9 +27,10 @@ import {
27
27
  } from "@frontmcp/sdk";
28
28
 
29
29
  // plugins/plugin-approval/src/approval/errors.ts
30
- var ApprovalError = class extends Error {
31
- constructor(message) {
32
- super(message);
30
+ import { PublicMcpError } from "@frontmcp/sdk";
31
+ var ApprovalError = class extends PublicMcpError {
32
+ constructor(message, code = "APPROVAL_REQUIRED", statusCode = 403) {
33
+ super(message, code, statusCode);
33
34
  this.name = "ApprovalError";
34
35
  }
35
36
  };
@@ -59,7 +60,7 @@ var ApprovalRequiredError = class extends ApprovalError {
59
60
  };
60
61
  var ApprovalOperationError = class extends ApprovalError {
61
62
  constructor(operation, reason) {
62
- super(`Approval ${operation} failed: ${reason}`);
63
+ super(`Approval ${operation} failed: ${reason}`, "APPROVAL_OPERATION_FAILED", 400);
63
64
  this.operation = operation;
64
65
  this.reason = reason;
65
66
  this.name = "ApprovalOperationError";
@@ -84,7 +85,9 @@ var ApprovalOperationError = class extends ApprovalError {
84
85
  var ApprovalScopeNotAllowedError = class extends ApprovalError {
85
86
  constructor(requestedScope, allowedScopes) {
86
87
  super(
87
- `Approval scope '${requestedScope}' is not allowed for this tool. Allowed scopes: ${allowedScopes.join(", ")}`
88
+ `Approval scope '${requestedScope}' is not allowed for this tool. Allowed scopes: ${allowedScopes.join(", ")}`,
89
+ "APPROVAL_SCOPE_NOT_ALLOWED",
90
+ 400
88
91
  );
89
92
  this.requestedScope = requestedScope;
90
93
  this.allowedScopes = allowedScopes;
@@ -110,7 +113,7 @@ var ApprovalScopeNotAllowedError = class extends ApprovalError {
110
113
  };
111
114
  var ApprovalExpiredError = class extends ApprovalError {
112
115
  constructor(toolId, expiredAt) {
113
- super(`Approval for tool '${toolId}' expired at ${new Date(expiredAt).toISOString()}`);
116
+ super(`Approval for tool '${toolId}' expired at ${new Date(expiredAt).toISOString()}`, "APPROVAL_EXPIRED", 403);
114
117
  this.toolId = toolId;
115
118
  this.expiredAt = expiredAt;
116
119
  this.name = "ApprovalExpiredError";
@@ -135,7 +138,7 @@ var ApprovalExpiredError = class extends ApprovalError {
135
138
  };
136
139
  var ChallengeValidationError = class extends ApprovalError {
137
140
  constructor(reason = "invalid", message) {
138
- super(message ?? `PKCE challenge validation failed: ${reason}`);
141
+ super(message ?? `PKCE challenge validation failed: ${reason}`, "CHALLENGE_VALIDATION_FAILED", 400);
139
142
  this.reason = reason;
140
143
  this.name = "ChallengeValidationError";
141
144
  }
@@ -589,7 +592,7 @@ ApprovalCheckPlugin = __decorateClass([
589
592
  ], ApprovalCheckPlugin);
590
593
 
591
594
  // plugins/plugin-approval/src/services/approval.service.ts
592
- import { Provider, ProviderScope } from "@frontmcp/sdk";
595
+ import { isAnonymousSubject, Provider, ProviderScope } from "@frontmcp/sdk";
593
596
  var ApprovalService = class {
594
597
  constructor(store, sessionId, userId, requirementOf = () => void 0) {
595
598
  this.store = store;
@@ -605,6 +608,24 @@ var ApprovalService = class {
605
608
  checkGrant(toolId, scope, ttlMs) {
606
609
  return checkGrantAgainstPolicy(toolId, scope, ttlMs, this.requirementOf(toolId));
607
610
  }
611
+ /** The caller's user id, when it names a principal: an anonymous subject (`anon:…`) names no one. */
612
+ get signedInUserId() {
613
+ return this.userId && !isAnonymousSubject(this.userId) ? this.userId : void 0;
614
+ }
615
+ /**
616
+ * Who a grant is recorded as when the call names no one: the signed-in user whose tool call made it.
617
+ * It used to be `'policy'`, so an audit trail showed every approval a user gave as a policy's.
618
+ * Without a signed-in user it is the store's default, a user with no identifier.
619
+ */
620
+ defaultGrantor() {
621
+ const userId = this.signedInUserId;
622
+ return userId ? userGrantor(userId) : { source: "user" };
623
+ }
624
+ /** Who a revocation is recorded as when the call names no one, by the same rule as a grant. */
625
+ defaultRevoker() {
626
+ const userId = this.signedInUserId;
627
+ return userId ? userRevoker(userId) : { source: "user" };
628
+ }
608
629
  // ─────────────────────────────────────────────────────────────────────────────
609
630
  // Query Methods
610
631
  // ─────────────────────────────────────────────────────────────────────────────
@@ -673,7 +694,7 @@ var ApprovalService = class {
673
694
  scope: "session" /* SESSION */,
674
695
  ttlMs,
675
696
  sessionId: this.sessionId,
676
- grantedBy: options.grantedBy ?? "policy",
697
+ grantedBy: options.grantedBy ?? this.defaultGrantor(),
677
698
  reason: options.reason,
678
699
  metadata: options.metadata
679
700
  });
@@ -691,7 +712,7 @@ var ApprovalService = class {
691
712
  scope: "user" /* USER */,
692
713
  ttlMs,
693
714
  userId: this.userId,
694
- grantedBy: options.grantedBy ?? "policy",
715
+ grantedBy: options.grantedBy ?? this.defaultGrantor(),
695
716
  reason: options.reason,
696
717
  metadata: options.metadata
697
718
  });
@@ -707,7 +728,7 @@ var ApprovalService = class {
707
728
  ttlMs,
708
729
  sessionId: this.sessionId,
709
730
  userId: this.userId,
710
- grantedBy: options.grantedBy ?? "policy",
731
+ grantedBy: options.grantedBy ?? this.defaultGrantor(),
711
732
  reason: options.reason,
712
733
  metadata: options.metadata
713
734
  });
@@ -724,7 +745,7 @@ var ApprovalService = class {
724
745
  context,
725
746
  sessionId: this.sessionId,
726
747
  userId: this.userId,
727
- grantedBy: options.grantedBy ?? "policy",
748
+ grantedBy: options.grantedBy ?? this.defaultGrantor(),
728
749
  reason: options.reason,
729
750
  metadata: options.metadata
730
751
  });
@@ -741,7 +762,7 @@ var ApprovalService = class {
741
762
  toolId,
742
763
  sessionId: this.sessionId,
743
764
  userId: this.userId,
744
- revokedBy: options.revokedBy ?? "policy",
765
+ revokedBy: options.revokedBy ?? this.defaultRevoker(),
745
766
  reason: options.reason
746
767
  });
747
768
  }
package/esm/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frontmcp/plugin-approval",
3
- "version": "1.8.5",
3
+ "version": "1.8.6",
4
4
  "description": "Approval plugin for FrontMCP - tool authorization workflow with PKCE webhook security",
5
5
  "author": "AgentFront <info@agentfront.dev>",
6
6
  "license": "Apache-2.0",
@@ -49,13 +49,13 @@
49
49
  }
50
50
  },
51
51
  "dependencies": {
52
- "@frontmcp/sdk": "1.8.5",
53
- "@frontmcp/utils": "1.8.5",
52
+ "@frontmcp/sdk": "1.8.6",
53
+ "@frontmcp/utils": "1.8.6",
54
54
  "ioredis": "^5.8.0",
55
55
  "reflect-metadata": "^0.2.2"
56
56
  },
57
57
  "peerDependencies": {
58
- "@frontmcp/lazy-zod": "1.8.5",
58
+ "@frontmcp/lazy-zod": "1.8.6",
59
59
  "@vercel/kv": "^2.0.0 || ^3.0.0"
60
60
  },
61
61
  "peerDependenciesMeta": {
package/index.js CHANGED
@@ -76,12 +76,13 @@ __export(index_exports, {
76
76
  module.exports = __toCommonJS(index_exports);
77
77
 
78
78
  // plugins/plugin-approval/src/approval.plugin.ts
79
- var import_sdk5 = require("@frontmcp/sdk");
79
+ var import_sdk6 = require("@frontmcp/sdk");
80
80
 
81
81
  // plugins/plugin-approval/src/approval/errors.ts
82
- var ApprovalError = class extends Error {
83
- constructor(message) {
84
- super(message);
82
+ var import_sdk = require("@frontmcp/sdk");
83
+ var ApprovalError = class extends import_sdk.PublicMcpError {
84
+ constructor(message, code = "APPROVAL_REQUIRED", statusCode = 403) {
85
+ super(message, code, statusCode);
85
86
  this.name = "ApprovalError";
86
87
  }
87
88
  };
@@ -111,7 +112,7 @@ var ApprovalRequiredError = class extends ApprovalError {
111
112
  };
112
113
  var ApprovalOperationError = class extends ApprovalError {
113
114
  constructor(operation, reason) {
114
- super(`Approval ${operation} failed: ${reason}`);
115
+ super(`Approval ${operation} failed: ${reason}`, "APPROVAL_OPERATION_FAILED", 400);
115
116
  this.operation = operation;
116
117
  this.reason = reason;
117
118
  this.name = "ApprovalOperationError";
@@ -136,7 +137,9 @@ var ApprovalOperationError = class extends ApprovalError {
136
137
  var ApprovalScopeNotAllowedError = class extends ApprovalError {
137
138
  constructor(requestedScope, allowedScopes) {
138
139
  super(
139
- `Approval scope '${requestedScope}' is not allowed for this tool. Allowed scopes: ${allowedScopes.join(", ")}`
140
+ `Approval scope '${requestedScope}' is not allowed for this tool. Allowed scopes: ${allowedScopes.join(", ")}`,
141
+ "APPROVAL_SCOPE_NOT_ALLOWED",
142
+ 400
140
143
  );
141
144
  this.requestedScope = requestedScope;
142
145
  this.allowedScopes = allowedScopes;
@@ -162,7 +165,7 @@ var ApprovalScopeNotAllowedError = class extends ApprovalError {
162
165
  };
163
166
  var ApprovalExpiredError = class extends ApprovalError {
164
167
  constructor(toolId, expiredAt) {
165
- super(`Approval for tool '${toolId}' expired at ${new Date(expiredAt).toISOString()}`);
168
+ super(`Approval for tool '${toolId}' expired at ${new Date(expiredAt).toISOString()}`, "APPROVAL_EXPIRED", 403);
166
169
  this.toolId = toolId;
167
170
  this.expiredAt = expiredAt;
168
171
  this.name = "ApprovalExpiredError";
@@ -187,7 +190,7 @@ var ApprovalExpiredError = class extends ApprovalError {
187
190
  };
188
191
  var ChallengeValidationError = class extends ApprovalError {
189
192
  constructor(reason = "invalid", message) {
190
- super(message ?? `PKCE challenge validation failed: ${reason}`);
193
+ super(message ?? `PKCE challenge validation failed: ${reason}`, "CHALLENGE_VALIDATION_FAILED", 400);
191
194
  this.reason = reason;
192
195
  this.name = "ChallengeValidationError";
193
196
  }
@@ -304,7 +307,7 @@ var ChallengeServiceToken = /* @__PURE__ */ Symbol.for(
304
307
  );
305
308
 
306
309
  // plugins/plugin-approval/src/hooks/approval-check.hook.ts
307
- var import_sdk = require("@frontmcp/sdk");
310
+ var import_sdk2 = require("@frontmcp/sdk");
308
311
 
309
312
  // plugins/plugin-approval/src/approval/schemas.ts
310
313
  var import_lazy_zod = require("@frontmcp/lazy-zod");
@@ -524,7 +527,7 @@ function isApiGrantor(grantor) {
524
527
 
525
528
  // plugins/plugin-approval/src/hooks/approval-check.hook.ts
526
529
  var passedApprovalStores = /* @__PURE__ */ new WeakMap();
527
- var ApprovalCheckPlugin = class extends import_sdk.DynamicPlugin {
530
+ var ApprovalCheckPlugin = class extends import_sdk2.DynamicPlugin {
528
531
  async checkApproval(flowCtx) {
529
532
  const { tool, toolContext } = flowCtx.state;
530
533
  if (!tool || !toolContext) return;
@@ -629,10 +632,10 @@ var ApprovalCheckPlugin = class extends import_sdk.DynamicPlugin {
629
632
  }
630
633
  };
631
634
  __decorateClass([
632
- import_sdk.ToolHook.Will("execute", { priority: 100, appliesTo: "uncovered-apps" })
635
+ import_sdk2.ToolHook.Will("execute", { priority: 100, appliesTo: "uncovered-apps" })
633
636
  ], ApprovalCheckPlugin.prototype, "checkApproval", 1);
634
637
  ApprovalCheckPlugin = __decorateClass([
635
- (0, import_sdk.Plugin)({
638
+ (0, import_sdk2.Plugin)({
636
639
  name: "approval:check",
637
640
  description: "Checks tool approval state before execution",
638
641
  // A server where a tool or agent declares `approval` and this gate does not reach it refuses to start.
@@ -641,7 +644,7 @@ ApprovalCheckPlugin = __decorateClass([
641
644
  ], ApprovalCheckPlugin);
642
645
 
643
646
  // plugins/plugin-approval/src/services/approval.service.ts
644
- var import_sdk2 = require("@frontmcp/sdk");
647
+ var import_sdk3 = require("@frontmcp/sdk");
645
648
  var ApprovalService = class {
646
649
  constructor(store, sessionId, userId, requirementOf = () => void 0) {
647
650
  this.store = store;
@@ -657,6 +660,24 @@ var ApprovalService = class {
657
660
  checkGrant(toolId, scope, ttlMs) {
658
661
  return checkGrantAgainstPolicy(toolId, scope, ttlMs, this.requirementOf(toolId));
659
662
  }
663
+ /** The caller's user id, when it names a principal: an anonymous subject (`anon:…`) names no one. */
664
+ get signedInUserId() {
665
+ return this.userId && !(0, import_sdk3.isAnonymousSubject)(this.userId) ? this.userId : void 0;
666
+ }
667
+ /**
668
+ * Who a grant is recorded as when the call names no one: the signed-in user whose tool call made it.
669
+ * It used to be `'policy'`, so an audit trail showed every approval a user gave as a policy's.
670
+ * Without a signed-in user it is the store's default, a user with no identifier.
671
+ */
672
+ defaultGrantor() {
673
+ const userId = this.signedInUserId;
674
+ return userId ? userGrantor(userId) : { source: "user" };
675
+ }
676
+ /** Who a revocation is recorded as when the call names no one, by the same rule as a grant. */
677
+ defaultRevoker() {
678
+ const userId = this.signedInUserId;
679
+ return userId ? userRevoker(userId) : { source: "user" };
680
+ }
660
681
  // ─────────────────────────────────────────────────────────────────────────────
661
682
  // Query Methods
662
683
  // ─────────────────────────────────────────────────────────────────────────────
@@ -725,7 +746,7 @@ var ApprovalService = class {
725
746
  scope: "session" /* SESSION */,
726
747
  ttlMs,
727
748
  sessionId: this.sessionId,
728
- grantedBy: options.grantedBy ?? "policy",
749
+ grantedBy: options.grantedBy ?? this.defaultGrantor(),
729
750
  reason: options.reason,
730
751
  metadata: options.metadata
731
752
  });
@@ -743,7 +764,7 @@ var ApprovalService = class {
743
764
  scope: "user" /* USER */,
744
765
  ttlMs,
745
766
  userId: this.userId,
746
- grantedBy: options.grantedBy ?? "policy",
767
+ grantedBy: options.grantedBy ?? this.defaultGrantor(),
747
768
  reason: options.reason,
748
769
  metadata: options.metadata
749
770
  });
@@ -759,7 +780,7 @@ var ApprovalService = class {
759
780
  ttlMs,
760
781
  sessionId: this.sessionId,
761
782
  userId: this.userId,
762
- grantedBy: options.grantedBy ?? "policy",
783
+ grantedBy: options.grantedBy ?? this.defaultGrantor(),
763
784
  reason: options.reason,
764
785
  metadata: options.metadata
765
786
  });
@@ -776,7 +797,7 @@ var ApprovalService = class {
776
797
  context,
777
798
  sessionId: this.sessionId,
778
799
  userId: this.userId,
779
- grantedBy: options.grantedBy ?? "policy",
800
+ grantedBy: options.grantedBy ?? this.defaultGrantor(),
780
801
  reason: options.reason,
781
802
  metadata: options.metadata
782
803
  });
@@ -793,7 +814,7 @@ var ApprovalService = class {
793
814
  toolId,
794
815
  sessionId: this.sessionId,
795
816
  userId: this.userId,
796
- revokedBy: options.revokedBy ?? "policy",
817
+ revokedBy: options.revokedBy ?? this.defaultRevoker(),
797
818
  reason: options.reason
798
819
  });
799
820
  }
@@ -805,10 +826,10 @@ var ApprovalService = class {
805
826
  }
806
827
  };
807
828
  ApprovalService = __decorateClass([
808
- (0, import_sdk2.Provider)({
829
+ (0, import_sdk3.Provider)({
809
830
  name: "provider:approval:service",
810
831
  description: "Service for managing tool approvals",
811
- scope: import_sdk2.ProviderScope.CONTEXT
832
+ scope: import_sdk3.ProviderScope.CONTEXT
812
833
  })
813
834
  ], ApprovalService);
814
835
  function createApprovalService(store, sessionId, userId, requirementOf) {
@@ -816,7 +837,7 @@ function createApprovalService(store, sessionId, userId, requirementOf) {
816
837
  }
817
838
 
818
839
  // plugins/plugin-approval/src/services/challenge.service.ts
819
- var import_sdk3 = require("@frontmcp/sdk");
840
+ var import_sdk4 = require("@frontmcp/sdk");
820
841
  var import_utils2 = require("@frontmcp/utils");
821
842
  var ChallengeService = class {
822
843
  storage;
@@ -950,10 +971,10 @@ var ChallengeService = class {
950
971
  }
951
972
  };
952
973
  ChallengeService = __decorateClass([
953
- (0, import_sdk3.Provider)({
974
+ (0, import_sdk4.Provider)({
954
975
  name: "provider:approval:challenge-service",
955
976
  description: "PKCE challenge service for webhook approval flows",
956
- scope: import_sdk3.ProviderScope.GLOBAL
977
+ scope: import_sdk4.ProviderScope.GLOBAL
957
978
  })
958
979
  ], ChallengeService);
959
980
  function generatePkcePairFromVerifier(codeVerifier) {
@@ -971,7 +992,7 @@ function createMemoryChallengeService(options = {}) {
971
992
  }
972
993
 
973
994
  // plugins/plugin-approval/src/stores/approval-storage.store.ts
974
- var import_sdk4 = require("@frontmcp/sdk");
995
+ var import_sdk5 = require("@frontmcp/sdk");
975
996
  var import_utils3 = require("@frontmcp/utils");
976
997
  function escapePattern(str) {
977
998
  return str.replace(/[*?[\]\\]/g, "\\$&");
@@ -1275,10 +1296,10 @@ var ApprovalStorageStore = class {
1275
1296
  }
1276
1297
  };
1277
1298
  ApprovalStorageStore = __decorateClass([
1278
- (0, import_sdk4.Provider)({
1299
+ (0, import_sdk5.Provider)({
1279
1300
  name: "provider:approval:store:storage",
1280
1301
  description: "Storage-backed approval store (supports Memory, Redis, Vercel KV, Upstash)",
1281
- scope: import_sdk4.ProviderScope.GLOBAL
1302
+ scope: import_sdk5.ProviderScope.GLOBAL
1282
1303
  })
1283
1304
  ], ApprovalStorageStore);
1284
1305
  function createApprovalMemoryStore(options = {}) {
@@ -1290,7 +1311,7 @@ function createApprovalMemoryStore(options = {}) {
1290
1311
  }
1291
1312
 
1292
1313
  // plugins/plugin-approval/src/approval.plugin.ts
1293
- var ApprovalPlugin = class extends import_sdk5.DynamicPlugin {
1314
+ var ApprovalPlugin = class extends import_sdk6.DynamicPlugin {
1294
1315
  options;
1295
1316
  constructor(options = {}) {
1296
1317
  super();
@@ -1351,8 +1372,8 @@ __publicField(ApprovalPlugin, "dynamicProviders", (options) => {
1351
1372
  providers.push({
1352
1373
  name: "approval:service",
1353
1374
  provide: ApprovalServiceToken,
1354
- scope: import_sdk5.ProviderScope.CONTEXT,
1355
- inject: () => [ApprovalStoreToken, import_sdk5.FRONTMCP_CONTEXT, import_sdk5.ScopeEntry],
1375
+ scope: import_sdk6.ProviderScope.CONTEXT,
1376
+ inject: () => [ApprovalStoreToken, import_sdk6.FRONTMCP_CONTEXT, import_sdk6.ScopeEntry],
1356
1377
  useFactory: (store, ctx, scope) => {
1357
1378
  const { sessionId, userId } = resolveApprovalIdentity(ctx);
1358
1379
  const requirementOf = (toolId) => {
@@ -1367,7 +1388,7 @@ __publicField(ApprovalPlugin, "dynamicProviders", (options) => {
1367
1388
  return providers;
1368
1389
  });
1369
1390
  ApprovalPlugin = __decorateClass([
1370
- (0, import_sdk5.Plugin)({
1391
+ (0, import_sdk6.Plugin)({
1371
1392
  name: "approval",
1372
1393
  description: "Tool authorization workflow with PKCE webhook security",
1373
1394
  plugins: [ApprovalCheckPlugin],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frontmcp/plugin-approval",
3
- "version": "1.8.5",
3
+ "version": "1.8.6",
4
4
  "description": "Approval plugin for FrontMCP - tool authorization workflow with PKCE webhook security",
5
5
  "author": "AgentFront <info@agentfront.dev>",
6
6
  "license": "Apache-2.0",
@@ -49,13 +49,13 @@
49
49
  }
50
50
  },
51
51
  "dependencies": {
52
- "@frontmcp/sdk": "1.8.5",
53
- "@frontmcp/utils": "1.8.5",
52
+ "@frontmcp/sdk": "1.8.6",
53
+ "@frontmcp/utils": "1.8.6",
54
54
  "ioredis": "^5.8.0",
55
55
  "reflect-metadata": "^0.2.2"
56
56
  },
57
57
  "peerDependencies": {
58
- "@frontmcp/lazy-zod": "1.8.5",
58
+ "@frontmcp/lazy-zod": "1.8.6",
59
59
  "@vercel/kv": "^2.0.0 || ^3.0.0"
60
60
  },
61
61
  "peerDependenciesMeta": {
@@ -14,7 +14,7 @@ export type ApprovalRequirementLookup = (toolId: string) => ToolApprovalRequirem
14
14
  * Options for granting approvals via the service.
15
15
  */
16
16
  export interface GrantOptions {
17
- /** Who/what is granting the approval (defaults to 'policy') */
17
+ /** Who/what is granting the approval (defaults to the signed-in user, or `{ source: 'user' }` without one) */
18
18
  grantedBy?: ApprovalGrantor | ApprovalSourceType;
19
19
  /** Optional reason for the approval */
20
20
  reason?: string;
@@ -25,7 +25,7 @@ export interface GrantOptions {
25
25
  * Options for revoking approvals via the service.
26
26
  */
27
27
  export interface RevokeOptions {
28
- /** Who/what is revoking the approval (defaults to 'policy') */
28
+ /** Who/what is revoking the approval (defaults to the signed-in user, or `{ source: 'user' }` without one) */
29
29
  revokedBy?: ApprovalRevoker | RevocationSourceType;
30
30
  /** Optional reason for revocation */
31
31
  reason?: string;
@@ -41,6 +41,16 @@ export declare class ApprovalService {
41
41
  constructor(store: ApprovalStore, sessionId: string, userId?: string | undefined, requirementOf?: ApprovalRequirementLookup);
42
42
  /** Checks a grant against the tool's `allowedScopes` and `maxTtlMs`; returns the ttl to store. */
43
43
  private checkGrant;
44
+ /** The caller's user id, when it names a principal: an anonymous subject (`anon:…`) names no one. */
45
+ private get signedInUserId();
46
+ /**
47
+ * Who a grant is recorded as when the call names no one: the signed-in user whose tool call made it.
48
+ * It used to be `'policy'`, so an audit trail showed every approval a user gave as a policy's.
49
+ * Without a signed-in user it is the store's default, a user with no identifier.
50
+ */
51
+ private defaultGrantor;
52
+ /** Who a revocation is recorded as when the call names no one, by the same rule as a grant. */
53
+ private defaultRevoker;
44
54
  /**
45
55
  * Check if a tool is approved for current session/user.
46
56
  */
@@ -1 +1 @@
1
- {"version":3,"file":"approval.service.d.ts","sourceRoot":"","sources":["../../src/services/approval.service.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACvF,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC7B,MAAM,UAAU,CAAC;AAElB;;;GAGG;AACH,MAAM,MAAM,yBAAyB,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,uBAAuB,GAAG,SAAS,CAAC;AAEhG;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,+DAA+D;IAC/D,SAAS,CAAC,EAAE,eAAe,GAAG,kBAAkB,CAAC;IACjD,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0BAA0B;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,+DAA+D;IAC/D,SAAS,CAAC,EAAE,eAAe,GAAG,oBAAoB,CAAC;IACnD,qCAAqC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,qBAKa,eAAe;IAExB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IACxB,OAAO,CAAC,QAAQ,CAAC,aAAa;gBAHb,KAAK,EAAE,aAAa,EACpB,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,MAAM,YAAA,EACf,aAAa,GAAE,yBAA2C;IAG7E,kGAAkG;IAClG,OAAO,CAAC,UAAU;IAQlB;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC;IAY7E;;OAEG;IACG,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC;IAItE;;OAEG;IACG,mBAAmB,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAQtD;;OAEG;IACG,gBAAgB,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAUnD;;;;OAIG;IACG,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAW9E;;OAEG;IACG,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,cAAc,CAAC;IAa/F;;OAEG;IACG,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,cAAc,CAAC;IAgB5F;;OAEG;IACG,wBAAwB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,cAAc,CAAC;IAclH;;OAEG;IACG,oBAAoB,CACxB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,eAAe,EACxB,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,cAAc,CAAC;IAmB1B;;;OAGG;IACG,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,OAAO,CAAC;IAUnF;;OAEG;IACG,qBAAqB,IAAI,OAAO,CAAC,MAAM,CAAC;CAG/C;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,aAAa,EACpB,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,MAAM,EACf,aAAa,CAAC,EAAE,yBAAyB,GACxC,eAAe,CAEjB"}
1
+ {"version":3,"file":"approval.service.d.ts","sourceRoot":"","sources":["../../src/services/approval.service.ts"],"names":[],"mappings":"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"}