@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.
- package/build/routes/oauth-server/authorize.js +4 -4
- package/build/services/auth/oauth-server/authorization.d.ts +5 -0
- package/build/services/auth/oauth-server/authorization.js +8 -0
- package/build/services/auth/oauth-server/metadata.d.ts +1 -1
- package/build/services/auth/oauth-server/metadata.js +2 -1
- package/docs/mcp.md +6 -1
- package/package.json +1 -1
|
@@ -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.
|
|
20
|
-
error: check.error, error_description: check.description, state: check.state,
|
|
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.
|
|
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.
|
|
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: [
|
|
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