@hotmeshio/long-tail 0.25.3 → 0.25.4

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.
@@ -16,8 +16,8 @@ function sendAuthorizationError(res, check, issuer, asJson) {
16
16
  res.status(400).json({ error: check.error, error_description: check.description });
17
17
  return;
18
18
  }
19
- const redirect = (0, authorization_1.withQuery)(check.redirectUri, {
20
- error: check.error, error_description: check.description, state: check.state, iss: issuer,
19
+ const redirect = (0, authorization_1.authorizationResponseUri)(check.redirectUri, issuer, {
20
+ error: check.error, error_description: check.description, state: check.state,
21
21
  });
22
22
  if (asJson)
23
23
  res.json({ redirect });
@@ -76,7 +76,7 @@ router.post('/authorize', auth_1.requireCredentialAuth, async (req, res) => {
76
76
  userId: req.auth.userId, clientId: client.client_id, policy: { preset }, scope: oauth_server_2.PRESET_SCOPE[preset],
77
77
  redirectUri, codeChallenge, resource, ttlSeconds: defaults_1.OAUTH_CODE_TTL_SECONDS,
78
78
  });
79
- res.json({ redirect: (0, authorization_1.withQuery)(redirectUri, { code, state, iss: settings.issuer }) });
79
+ res.json({ redirect: (0, authorization_1.authorizationResponseUri)(redirectUri, settings.issuer, { code, state }) });
80
80
  });
81
81
  /**
82
82
  * POST /api/oauth/deny
@@ -93,7 +93,7 @@ router.post('/deny', auth_1.requireCredentialAuth, async (req, res) => {
93
93
  return;
94
94
  }
95
95
  const state = typeof req.body?.state === 'string' ? req.body.state : undefined;
96
- res.json({ redirect: (0, authorization_1.withQuery)(redirectUri, { error: 'access_denied', state, iss: settings.issuer }) });
96
+ res.json({ redirect: (0, authorization_1.authorizationResponseUri)(redirectUri, settings.issuer, { error: 'access_denied', state }) });
97
97
  });
98
98
  /**
99
99
  * GET /api/oauth/clients/:id
@@ -37,6 +37,11 @@ export declare function checkAuthorizationRequest(params: Record<string, unknown
37
37
  export declare function isGrantPreset(value: unknown): value is LTGrantPreset;
38
38
  /** `uri` with `params` added to its query, keeping any query it already has. */
39
39
  export declare function withQuery(uri: string, params: Record<string, string | undefined>): string;
40
+ /**
41
+ * The client's redirect for an authorization response, a code or an error.
42
+ * Always carries `iss` (RFC 9207), as the server metadata advertises.
43
+ */
44
+ export declare function authorizationResponseUri(redirectUri: string, issuer: string, params: Record<string, string | undefined>): string;
40
45
  /**
41
46
  * The presets the person may grant. Read-only always; Just be me only when it
42
47
  * adds something: a membership that can write, or an admin tier.
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.checkAuthorizationRequest = checkAuthorizationRequest;
4
4
  exports.isGrantPreset = isGrantPreset;
5
5
  exports.withQuery = withQuery;
6
+ exports.authorizationResponseUri = authorizationResponseUri;
6
7
  exports.grantablePresets = grantablePresets;
7
8
  const registration_1 = require("./registration");
8
9
  const store_1 = require("./store");
@@ -44,6 +45,13 @@ function withQuery(uri, params) {
44
45
  url.searchParams.set(key, value);
45
46
  return url.toString();
46
47
  }
48
+ /**
49
+ * The client's redirect for an authorization response, a code or an error.
50
+ * Always carries `iss` (RFC 9207), as the server metadata advertises.
51
+ */
52
+ function authorizationResponseUri(redirectUri, issuer, params) {
53
+ return withQuery(redirectUri, { ...params, iss: issuer });
54
+ }
47
55
  /**
48
56
  * The presets the person may grant. Read-only always; Just be me only when it
49
57
  * adds something: a membership that can write, or an admin tier.
@@ -6,7 +6,7 @@ export declare const OAUTH_ENDPOINT_PATHS: {
6
6
  readonly REGISTER: "/api/oauth/register";
7
7
  readonly REVOKE: "/api/oauth/revoke";
8
8
  };
9
- /** RFC 8414 authorization server metadata. */
9
+ /** RFC 8414 authorization server metadata. Authorization responses carry `iss` (RFC 9207). */
10
10
  export declare function authorizationServerMetadata(settings: OAuthServerSettings): Record<string, unknown>;
11
11
  /** RFC 9728 protected resource metadata for `/mcp`. */
12
12
  export declare function protectedResourceMetadata(settings: OAuthServerSettings): Record<string, unknown>;
@@ -13,7 +13,7 @@ exports.OAUTH_ENDPOINT_PATHS = {
13
13
  REVOKE: '/api/oauth/revoke',
14
14
  };
15
15
  const SCOPES_SUPPORTED = [constants_1.MCP_SCOPES.READ, constants_1.MCP_SCOPES.FULL];
16
- /** RFC 8414 authorization server metadata. */
16
+ /** RFC 8414 authorization server metadata. Authorization responses carry `iss` (RFC 9207). */
17
17
  function authorizationServerMetadata(settings) {
18
18
  const at = (path) => `${settings.issuer}${path}`;
19
19
  return {
@@ -28,6 +28,7 @@ function authorizationServerMetadata(settings) {
28
28
  token_endpoint_auth_methods_supported: ['none'],
29
29
  revocation_endpoint_auth_methods_supported: ['none'],
30
30
  scopes_supported: SCOPES_SUPPORTED,
31
+ authorization_response_iss_parameter_supported: true,
31
32
  };
32
33
  }
33
34
  /** RFC 9728 protected resource metadata for `/mcp`. */
package/docs/mcp.md CHANGED
@@ -216,7 +216,10 @@ start({
216
216
  auth: {
217
217
  oauthServer: {
218
218
  issuer: 'https://api.example.com/longtail', // the public base URL Long Tail is served under
219
- allowedRedirectUris: ['https://claude.ai/api/mcp/auth_callback'], // exact https redirects, beyond loopback
219
+ allowedRedirectUris: [ // exact https redirects, beyond loopback
220
+ 'https://claude.ai/api/mcp/auth_callback',
221
+ 'https://chatgpt.com/connector_platform_oauth_redirect',
222
+ ],
220
223
  },
221
224
  },
222
225
  });
@@ -224,6 +227,8 @@ start({
224
227
 
225
228
  Clients register themselves (RFC 7591). Loopback redirects (`http://127.0.0.1`, `localhost`, `[::1]`, any port) are always allowed, which covers Claude Code and Claude Desktop; an `https` redirect is allowed only when it equals a URI in `allowedRedirectUris`.
226
229
 
230
+ Every authorization response, a code or an error, carries the issuer as `iss` (RFC 9207), and the server metadata advertises it with `authorization_response_iss_parameter_supported`. Clients that check the issuer use one fixed callback for every connection, which a single `allowedRedirectUris` entry covers: ChatGPT's is `https://chatgpt.com/connector_platform_oauth_redirect`.
231
+
227
232
  **Embedded deployments** mount two routers, and let four paths reach Long Tail without the host's login:
228
233
 
229
234
  - `adapter.getRouter()` under the base path, as today, and `adapter.getWellKnownRouter()` at the host's root. The well-known router answers only its two documents and passes every other request on.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hotmeshio/long-tail",
3
- "version": "0.25.3",
3
+ "version": "0.25.4",
4
4
  "description": "Long Tail Workflows — Durable AI workflows with human-in-the-loop escalation. Powered by PostgreSQL.",
5
5
  "main": "./build/index.js",
6
6
  "types": "./build/index.d.ts",