@honeyfield/rent2b-mcp 1.3.0 → 1.4.1
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/auth/authorize-page.d.ts +0 -7
- package/dist/auth/authorize-page.js +6 -39
- package/dist/auth/authorize-page.js.map +1 -1
- package/dist/auth/http-oauth.d.ts +12 -6
- package/dist/auth/http-oauth.js +76 -31
- package/dist/auth/http-oauth.js.map +1 -1
- package/dist/auth/social.d.ts +40 -0
- package/dist/auth/social.js +58 -0
- package/dist/auth/social.js.map +1 -0
- package/dist/config.d.ts +6 -2
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -1
- package/dist/index.js +12 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -8,13 +8,6 @@ export interface AuthorizePageParams {
|
|
|
8
8
|
resource: string;
|
|
9
9
|
}
|
|
10
10
|
export declare function renderAuthorizePage(p: AuthorizePageParams, errorMessage?: string, showSocial?: boolean): string;
|
|
11
|
-
/**
|
|
12
|
-
* Page shown after the social provider redirects back. The Supabase session
|
|
13
|
-
* arrives in the URL fragment (`#access_token=…&refresh_token=…`), which is only
|
|
14
|
-
* readable client-side, so this tiny script lifts it out and re-submits it (with
|
|
15
|
-
* the preserved OAuth-flow fields) to /authorize/submit as a normal form post.
|
|
16
|
-
*/
|
|
17
|
-
export declare function renderSocialCallbackPage(params: Record<string, string>): string;
|
|
18
11
|
interface FlowFields {
|
|
19
12
|
clientId: string;
|
|
20
13
|
redirectUri: string;
|
|
@@ -28,10 +28,13 @@ const STYLE = `
|
|
|
28
28
|
h1 { font-size: 1.25rem; } label { display:block; margin: .9rem 0 .25rem; font-weight: 600; }
|
|
29
29
|
input { width: 100%; padding: .6rem; font-size: 1rem; border: 1px solid #bbb; border-radius: .4rem; box-sizing: border-box; }
|
|
30
30
|
button { margin-top: 1.1rem; width: 100%; padding: .65rem 1.2rem; font-size: 1rem; border: 0; border-radius: .4rem; background: #111; color: #fff; cursor: pointer; }
|
|
31
|
-
.sso { display:
|
|
31
|
+
.sso { display:flex; align-items:center; justify-content:center; gap:.6rem; margin-top:.6rem; padding:.6rem; border:1px solid #ccc; border-radius:.4rem; text-decoration:none; color:#111; background:#fff; font-weight:500; }
|
|
32
|
+
.sso:hover { background:#f7f7f7; } .sso svg { flex:0 0 auto; }
|
|
32
33
|
.divider { text-align:center; color:#999; margin:1.2rem 0 .4rem; font-size:.8rem; }
|
|
33
34
|
p.hint { color: #555; font-size: .85rem; } .err { color:#b00020; font-size:.9rem; margin:.5rem 0; }
|
|
34
35
|
`;
|
|
36
|
+
const GOOGLE_ICON = '<svg width="18" height="18" viewBox="0 0 48 48" aria-hidden="true"><path fill="#FFC107" d="M43.6 20.5H42V20H24v8h11.3c-1.6 4.7-6.1 8-11.3 8-6.6 0-12-5.4-12-12s5.4-12 12-12c3.1 0 5.9 1.2 8 3.1l5.7-5.7C34.6 6.1 29.6 4 24 4 12.9 4 4 12.9 4 24s8.9 20 20 20 20-8.9 20-20c0-1.3-.1-2.3-.4-3.5z"/><path fill="#FF3D00" d="M6.3 14.7l6.6 4.8C14.7 16 19 13 24 13c3.1 0 5.9 1.2 8 3.1l5.7-5.7C34.6 6.1 29.6 4 24 4 16.3 4 9.7 8.3 6.3 14.7z"/><path fill="#4CAF50" d="M24 44c5.5 0 10.5-2.1 14.3-5.5l-6.6-5.6C29.6 34.6 26.9 36 24 36c-5.2 0-9.6-3.3-11.3-7.9l-6.5 5C9.6 39.6 16.2 44 24 44z"/><path fill="#1976D2" d="M43.6 20.5H42V20H24v8h11.3c-.8 2.3-2.3 4.3-4.3 5.6l6.6 5.6C41.4 36.4 44 30.7 44 24c0-1.3-.1-2.3-.4-3.5z"/></svg>';
|
|
37
|
+
const APPLE_ICON = '<svg width="16" height="16" viewBox="0 0 384 512" fill="#000" aria-hidden="true"><path d="M318.7 268.7c-.2-36.7 16.4-64.4 50-84.8-18.8-26.9-47.2-41.7-84.7-44.6-35.5-2.8-74.3 20.7-88.5 20.7-15 0-49.4-19.7-76.4-19.7C63.3 141.2 4 184.8 4 273.5q0 39.3 14.4 81.2c12.8 36.7 59 126.7 107.2 125.2 25.2-.6 43-17.9 75.8-17.9 31.8 0 48.3 17.9 76.4 17.9 48.6-.7 90.4-82.5 102.6-119.3-65.2-30.7-61.7-90-61.7-91.9zm-56.6-164.2c27.3-32.4 24.8-61.9 24-72.5-24.1 1.4-52 16.4-67.9 34.9-17.5 19.8-27.8 44.3-25.6 71.9 26.1 2 49.9-11.4 69.5-34.3z"/></svg>';
|
|
35
38
|
export function renderAuthorizePage(p, errorMessage, showSocial = false) {
|
|
36
39
|
const appName = p.clientName ? esc(p.clientName) : 'this application';
|
|
37
40
|
const q = esc(flowQuery(p));
|
|
@@ -40,8 +43,8 @@ export function renderAuthorizePage(p, errorMessage, showSocial = false) {
|
|
|
40
43
|
// off until that path is verified (see RENT2B_MCP_SOCIAL_LOGIN).
|
|
41
44
|
const social = showSocial
|
|
42
45
|
? `<div class="divider">or</div>
|
|
43
|
-
<a class="sso" href="authorize/social?provider=google&${q}"
|
|
44
|
-
<a class="sso" href="authorize/social?provider=apple&${q}"
|
|
46
|
+
<a class="sso" href="authorize/social?provider=google&${q}">${GOOGLE_ICON}Continue with Google</a>
|
|
47
|
+
<a class="sso" href="authorize/social?provider=apple&${q}">${APPLE_ICON}Continue with Apple</a>`
|
|
45
48
|
: '';
|
|
46
49
|
// action/href are relative so they resolve under the gateway path prefix
|
|
47
50
|
// (/rent2b/authorize/submit, /rent2b/authorize/social).
|
|
@@ -69,42 +72,6 @@ export function renderAuthorizePage(p, errorMessage, showSocial = false) {
|
|
|
69
72
|
</body>
|
|
70
73
|
</html>`;
|
|
71
74
|
}
|
|
72
|
-
/**
|
|
73
|
-
* Page shown after the social provider redirects back. The Supabase session
|
|
74
|
-
* arrives in the URL fragment (`#access_token=…&refresh_token=…`), which is only
|
|
75
|
-
* readable client-side, so this tiny script lifts it out and re-submits it (with
|
|
76
|
-
* the preserved OAuth-flow fields) to /authorize/submit as a normal form post.
|
|
77
|
-
*/
|
|
78
|
-
export function renderSocialCallbackPage(params) {
|
|
79
|
-
const fields = Object.entries(params)
|
|
80
|
-
.map(([k, v]) => hidden(k, v))
|
|
81
|
-
.join('\n ');
|
|
82
|
-
return `<!doctype html>
|
|
83
|
-
<html lang="en"><head><meta charset="utf-8"><title>Signing you in…</title>
|
|
84
|
-
<style>${STYLE}</style></head>
|
|
85
|
-
<body>
|
|
86
|
-
<p class="hint">Completing sign-in…</p>
|
|
87
|
-
<form id="f" method="post" action="submit">
|
|
88
|
-
${fields}
|
|
89
|
-
<input type="hidden" name="access_token" id="at">
|
|
90
|
-
<input type="hidden" name="refresh_token" id="rt">
|
|
91
|
-
<noscript><p class="err">JavaScript is required to finish signing in.</p></noscript>
|
|
92
|
-
</form>
|
|
93
|
-
<script>
|
|
94
|
-
(function () {
|
|
95
|
-
var h = new URLSearchParams((location.hash || '').replace(/^#/, ''));
|
|
96
|
-
var at = h.get('access_token'), rt = h.get('refresh_token');
|
|
97
|
-
if (at && rt) {
|
|
98
|
-
document.getElementById('at').value = at;
|
|
99
|
-
document.getElementById('rt').value = rt;
|
|
100
|
-
document.getElementById('f').submit();
|
|
101
|
-
} else {
|
|
102
|
-
document.body.textContent = 'Sign-in did not return a session. Please try again.';
|
|
103
|
-
}
|
|
104
|
-
})();
|
|
105
|
-
</script>
|
|
106
|
-
</body></html>`;
|
|
107
|
-
}
|
|
108
75
|
export function parseAuthorizeSubmit(body) {
|
|
109
76
|
const str = (k) => {
|
|
110
77
|
const v = body[k];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authorize-page.js","sourceRoot":"","sources":["../../src/auth/authorize-page.ts"],"names":[],"mappings":"AAUA,SAAS,GAAG,CAAC,KAAa;IACxB,OAAO,KAAK;SACT,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAC3B,CAAC;AAED,SAAS,MAAM,CAAC,IAAY,EAAE,KAAa;IACzC,OAAO,8BAA8B,GAAG,CAAC,IAAI,CAAC,YAAY,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;AAC3E,CAAC;AAED,0FAA0F;AAC1F,MAAM,WAAW,GAAG;IAClB,UAAU;IACV,aAAa;IACb,OAAO;IACP,eAAe;IACf,QAAQ;IACR,UAAU;CACF,CAAC;AAEX,SAAS,SAAS,CAAC,CAAsB;IACvC,MAAM,CAAC,GAAG,IAAI,eAAe,EAAE,CAAC;IAChC,KAAK,MAAM,CAAC,IAAI,WAAW;QAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAClD,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC;AACtB,CAAC;AAED,MAAM,KAAK,GAAG
|
|
1
|
+
{"version":3,"file":"authorize-page.js","sourceRoot":"","sources":["../../src/auth/authorize-page.ts"],"names":[],"mappings":"AAUA,SAAS,GAAG,CAAC,KAAa;IACxB,OAAO,KAAK;SACT,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAC3B,CAAC;AAED,SAAS,MAAM,CAAC,IAAY,EAAE,KAAa;IACzC,OAAO,8BAA8B,GAAG,CAAC,IAAI,CAAC,YAAY,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;AAC3E,CAAC;AAED,0FAA0F;AAC1F,MAAM,WAAW,GAAG;IAClB,UAAU;IACV,aAAa;IACb,OAAO;IACP,eAAe;IACf,QAAQ;IACR,UAAU;CACF,CAAC;AAEX,SAAS,SAAS,CAAC,CAAsB;IACvC,MAAM,CAAC,GAAG,IAAI,eAAe,EAAE,CAAC;IAChC,KAAK,MAAM,CAAC,IAAI,WAAW;QAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAClD,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC;AACtB,CAAC;AAED,MAAM,KAAK,GAAG;;;;;;;;;CASb,CAAC;AAEF,MAAM,WAAW,GACf,ssBAAssB,CAAC;AACzsB,MAAM,UAAU,GACd,whBAAwhB,CAAC;AAE3hB,MAAM,UAAU,mBAAmB,CACjC,CAAsB,EACtB,YAAqB,EACrB,UAAU,GAAG,KAAK;IAElB,MAAM,OAAO,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC;IACtE,MAAM,CAAC,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5B,MAAM,GAAG,GAAG,YAAY,CAAC,CAAC,CAAC,kBAAkB,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1E,4EAA4E;IAC5E,iEAAiE;IACjE,MAAM,MAAM,GAAG,UAAU;QACvB,CAAC,CAAC;8DACwD,CAAC,KAAK,WAAW;6DAClB,CAAC,KAAK,UAAU,yBAAyB;QAClG,CAAC,CAAC,EAAE,CAAC;IACP,yEAAyE;IACzE,wDAAwD;IACxD,OAAO;;;;;;SAMA,KAAK;;;2BAGa,OAAO;;IAE9B,GAAG;;MAED,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC;;;;;;;IAO9D,MAAM;;QAEF,CAAC;AACT,CAAC;AAaD,MAAM,UAAU,oBAAoB,CAClC,IAA6B;IAE7B,MAAM,GAAG,GAAG,CAAC,CAAS,EAAU,EAAE;QAChC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC;QACpF,OAAO,CAAC,CAAC;IACX,CAAC,CAAC;IACF,MAAM,IAAI,GAAe;QACvB,QAAQ,EAAE,GAAG,CAAC,UAAU,CAAC;QACzB,WAAW,EAAE,GAAG,CAAC,aAAa,CAAC;QAC/B,KAAK,EAAE,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;QACvD,aAAa,EAAE,GAAG,CAAC,eAAe,CAAC;KACpC,CAAC;IAEF,IAAI,OAAO,IAAI,CAAC,YAAY,KAAK,QAAQ,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1E,OAAO;YACL,IAAI,EAAE,SAAS;YACf,WAAW,EAAE,GAAG,CAAC,cAAc,CAAC;YAChC,YAAY,EAAE,GAAG,CAAC,eAAe,CAAC;YAClC,GAAG,IAAI;SACR,CAAC;IACJ,CAAC;IACD,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC;QACnB,QAAQ,EAAE,GAAG,CAAC,UAAU,CAAC;QACzB,GAAG,IAAI;KACR,CAAC;AACJ,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,gBAAgB,CAAC,KAA8B;IAI7D,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC;IACjE,MAAM,IAAI,GAA2B,EAAE,CAAC;IACxC,KAAK,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC;QAC5B,IAAI,CAAC,CAAC,CAAC,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAE,KAAK,CAAC,CAAC,CAAY,CAAC,CAAC,CAAC,EAAE,CAAC;IACrE,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;QAC/D,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAC5B,CAAC"}
|
|
@@ -2,21 +2,27 @@ import { type Express, type RequestHandler } from 'express';
|
|
|
2
2
|
import type { OAuthRuntimeConfig } from './oauth-config.js';
|
|
3
3
|
import type { Rent2bOAuthProvider } from './provider.js';
|
|
4
4
|
import type { ApiAuthClient } from './api-auth.js';
|
|
5
|
+
import { type SupabaseOAuthClient, type SocialFlowStore } from './social.js';
|
|
6
|
+
export interface SocialDeps {
|
|
7
|
+
oauth: SupabaseOAuthClient;
|
|
8
|
+
store: SocialFlowStore;
|
|
9
|
+
}
|
|
5
10
|
export interface RegisterOAuthOptions {
|
|
6
11
|
oauthCfg: OAuthRuntimeConfig;
|
|
7
12
|
provider: Rent2bOAuthProvider;
|
|
8
13
|
apiAuth: ApiAuthClient;
|
|
9
|
-
/**
|
|
10
|
-
|
|
14
|
+
/** When set, enables server-side Google/Apple social login. */
|
|
15
|
+
social?: SocialDeps;
|
|
11
16
|
}
|
|
12
17
|
/**
|
|
13
18
|
* Wires the OAuth 2.1 + DCR surface onto an Express app and returns the
|
|
14
19
|
* bearer-auth middleware to guard the MCP endpoint.
|
|
15
20
|
*
|
|
16
|
-
* Login is the user's own rent2b account
|
|
17
|
-
*
|
|
18
|
-
* resulting Supabase session (see
|
|
19
|
-
* bearer tokens and `X-API-Key` headers
|
|
21
|
+
* Login is the user's own rent2b account: email/password (delegated to the
|
|
22
|
+
* rent2b-api auth endpoints) or Google/Apple (a server-side Supabase PKCE flow
|
|
23
|
+
* run here). The issued token carries the resulting Supabase session (see
|
|
24
|
+
* provider.mintSessionTokens). Raw `r2b_` bearer tokens and `X-API-Key` headers
|
|
25
|
+
* still work (backward compat).
|
|
20
26
|
*
|
|
21
27
|
* Note on path-prefixed deployment: the MCP SDK serves the auth handlers at the
|
|
22
28
|
* origin root and advertises them origin-level, dropping any issuer path.
|
package/dist/auth/http-oauth.js
CHANGED
|
@@ -1,19 +1,33 @@
|
|
|
1
1
|
import express from 'express';
|
|
2
2
|
import { mcpAuthRouter, getOAuthProtectedResourceMetadataUrl, } from '@modelcontextprotocol/sdk/server/auth/router.js';
|
|
3
3
|
import { requireBearerAuth } from '@modelcontextprotocol/sdk/server/auth/middleware/bearerAuth.js';
|
|
4
|
-
import {
|
|
5
|
-
|
|
4
|
+
import { generatePkce, } from './social.js';
|
|
5
|
+
import { parseAuthorizeSubmit, parseSocialStart, renderAuthorizePage, } from './authorize-page.js';
|
|
6
6
|
function str(v) {
|
|
7
7
|
return typeof v === 'string' ? v : '';
|
|
8
8
|
}
|
|
9
|
+
/** OAuth error redirect back to the client's callback (RFC 6749 §4.1.2.1). */
|
|
10
|
+
function redirectError(res, redirectUri, state, error) {
|
|
11
|
+
try {
|
|
12
|
+
const url = new URL(redirectUri);
|
|
13
|
+
url.searchParams.set('error', error);
|
|
14
|
+
if (state)
|
|
15
|
+
url.searchParams.set('state', state);
|
|
16
|
+
res.redirect(302, url.toString());
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
res.status(400).send(`Sign-in failed: ${error}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
9
22
|
/**
|
|
10
23
|
* Wires the OAuth 2.1 + DCR surface onto an Express app and returns the
|
|
11
24
|
* bearer-auth middleware to guard the MCP endpoint.
|
|
12
25
|
*
|
|
13
|
-
* Login is the user's own rent2b account
|
|
14
|
-
*
|
|
15
|
-
* resulting Supabase session (see
|
|
16
|
-
* bearer tokens and `X-API-Key` headers
|
|
26
|
+
* Login is the user's own rent2b account: email/password (delegated to the
|
|
27
|
+
* rent2b-api auth endpoints) or Google/Apple (a server-side Supabase PKCE flow
|
|
28
|
+
* run here). The issued token carries the resulting Supabase session (see
|
|
29
|
+
* provider.mintSessionTokens). Raw `r2b_` bearer tokens and `X-API-Key` headers
|
|
30
|
+
* still work (backward compat).
|
|
17
31
|
*
|
|
18
32
|
* Note on path-prefixed deployment: the MCP SDK serves the auth handlers at the
|
|
19
33
|
* origin root and advertises them origin-level, dropping any issuer path.
|
|
@@ -22,7 +36,8 @@ function str(v) {
|
|
|
22
36
|
* advertise the wrong (origin-level) URLs, so we override that one document.
|
|
23
37
|
*/
|
|
24
38
|
export function registerOAuth(app, opts) {
|
|
25
|
-
const { oauthCfg, provider, apiAuth,
|
|
39
|
+
const { oauthCfg, provider, apiAuth, social } = opts;
|
|
40
|
+
const socialLogin = !!social;
|
|
26
41
|
const issuerHref = oauthCfg.issuerUrl.href.replace(/\/$/, '');
|
|
27
42
|
app.use(express.urlencoded({ extended: false }));
|
|
28
43
|
const authServerMetadata = {
|
|
@@ -46,10 +61,10 @@ export function registerOAuth(app, opts) {
|
|
|
46
61
|
resourceServerUrl: oauthCfg.resourceUrl,
|
|
47
62
|
scopesSupported: [],
|
|
48
63
|
}));
|
|
49
|
-
// Step 1 of social login:
|
|
50
|
-
//
|
|
51
|
-
app.get('/authorize/social',
|
|
52
|
-
if (!
|
|
64
|
+
// Step 1 of social login: start a Supabase PKCE flow and bounce the browser
|
|
65
|
+
// to the provider. The verifier is kept server-side, keyed by `sid`.
|
|
66
|
+
app.get('/authorize/social', (req, res) => {
|
|
67
|
+
if (!social) {
|
|
53
68
|
res.status(404).send('Social login is not enabled');
|
|
54
69
|
return;
|
|
55
70
|
}
|
|
@@ -61,31 +76,61 @@ export function registerOAuth(app, opts) {
|
|
|
61
76
|
res.status(400).send('Missing OAuth flow parameters');
|
|
62
77
|
return;
|
|
63
78
|
}
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
79
|
+
const { verifier, challenge } = generatePkce();
|
|
80
|
+
const sid = social.store.create({
|
|
81
|
+
verifier,
|
|
82
|
+
clientId: parsed.flow.clientId,
|
|
83
|
+
redirectUri: parsed.flow.redirectUri,
|
|
84
|
+
state: parsed.flow.state,
|
|
85
|
+
codeChallenge: parsed.flow.codeChallenge,
|
|
86
|
+
});
|
|
87
|
+
const redirectTo = `${issuerHref}/authorize/callback?sid=${sid}`;
|
|
88
|
+
res.redirect(302, social.oauth.authorizeUrl(parsed.provider, redirectTo, challenge));
|
|
74
89
|
});
|
|
75
|
-
// Step 2 of social login:
|
|
76
|
-
//
|
|
77
|
-
app.get('/authorize/callback', (req, res) => {
|
|
78
|
-
if (!
|
|
90
|
+
// Step 2 of social login: PKCE returns `?code=` (server-readable). Exchange it
|
|
91
|
+
// for a Supabase session, then issue our own auth code to the MCP client.
|
|
92
|
+
app.get('/authorize/callback', async (req, res) => {
|
|
93
|
+
if (!social) {
|
|
79
94
|
res.status(404).send('Social login is not enabled');
|
|
80
95
|
return;
|
|
81
96
|
}
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
97
|
+
const q = req.query;
|
|
98
|
+
const flow = social.store.take(str(q.sid));
|
|
99
|
+
if (!flow) {
|
|
100
|
+
res.status(400).send('Login session expired — please start again.');
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const providerError = str(q.error);
|
|
104
|
+
if (providerError) {
|
|
105
|
+
redirectError(res, flow.redirectUri, flow.state, providerError);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const code = str(q.code);
|
|
109
|
+
if (!code) {
|
|
110
|
+
redirectError(res, flow.redirectUri, flow.state, 'access_denied');
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
try {
|
|
114
|
+
const session = await social.oauth.exchangeCode(code, flow.verifier);
|
|
115
|
+
const orgId = await apiAuth.resolveOrg(session.access_token);
|
|
116
|
+
const ourCode = provider.issueAuthCode({
|
|
117
|
+
session,
|
|
118
|
+
orgId,
|
|
119
|
+
codeChallenge: flow.codeChallenge,
|
|
120
|
+
redirectUri: flow.redirectUri,
|
|
121
|
+
clientId: flow.clientId,
|
|
122
|
+
});
|
|
123
|
+
const redirect = new URL(flow.redirectUri);
|
|
124
|
+
redirect.searchParams.set('code', ourCode);
|
|
125
|
+
if (flow.state)
|
|
126
|
+
redirect.searchParams.set('state', flow.state);
|
|
127
|
+
res.redirect(302, redirect.toString());
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
redirectError(res, flow.redirectUri, flow.state, 'server_error');
|
|
131
|
+
}
|
|
87
132
|
});
|
|
88
|
-
// The login page (provider.authorize)
|
|
133
|
+
// The email/password login page (provider.authorize) posts here.
|
|
89
134
|
app.post('/authorize/submit', async (req, res) => {
|
|
90
135
|
const body = req.body;
|
|
91
136
|
let fields;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-oauth.js","sourceRoot":"","sources":["../../src/auth/http-oauth.ts"],"names":[],"mappings":"AAAA,OAAO,OAA8C,MAAM,SAAS,CAAC;AACrE,OAAO,EACL,aAAa,EACb,oCAAoC,GACrC,MAAM,iDAAiD,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gEAAgE,CAAC;AAInG,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,mBAAmB,
|
|
1
|
+
{"version":3,"file":"http-oauth.js","sourceRoot":"","sources":["../../src/auth/http-oauth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { SupabaseSession } from './api-auth.js';
|
|
2
|
+
/**
|
|
3
|
+
* Server-side social login (Google/Apple) against Supabase GoTrue, run entirely
|
|
4
|
+
* by the MCP so it works for a headless connector.
|
|
5
|
+
*
|
|
6
|
+
* We drive the PKCE flow ourselves: generate the verifier/challenge, redirect
|
|
7
|
+
* the browser to GoTrue `/authorize`, and — because PKCE returns `?code=` on the
|
|
8
|
+
* redirect (readable server-side, unlike the implicit `#fragment`) — exchange
|
|
9
|
+
* the code for a session in the callback with no client-side JavaScript. The
|
|
10
|
+
* verifier is held in `SocialFlowStore`, keyed by an opaque `sid` carried in the
|
|
11
|
+
* redirect URL, and never leaves the server.
|
|
12
|
+
*/
|
|
13
|
+
export interface SocialFlow {
|
|
14
|
+
verifier: string;
|
|
15
|
+
clientId: string;
|
|
16
|
+
redirectUri: string;
|
|
17
|
+
state: string;
|
|
18
|
+
codeChallenge: string;
|
|
19
|
+
expiresAt: number;
|
|
20
|
+
}
|
|
21
|
+
export declare class SocialFlowStore {
|
|
22
|
+
private flows;
|
|
23
|
+
/** Store a pending flow and return its opaque id. */
|
|
24
|
+
create(flow: Omit<SocialFlow, 'expiresAt'>): string;
|
|
25
|
+
/** Consume a flow exactly once; undefined if unknown or expired. */
|
|
26
|
+
take(sid: string): SocialFlow | undefined;
|
|
27
|
+
}
|
|
28
|
+
export declare function generatePkce(): {
|
|
29
|
+
verifier: string;
|
|
30
|
+
challenge: string;
|
|
31
|
+
};
|
|
32
|
+
export declare class SupabaseOAuthClient {
|
|
33
|
+
private readonly url;
|
|
34
|
+
private readonly anonKey;
|
|
35
|
+
constructor(url: string, anonKey: string);
|
|
36
|
+
/** GoTrue `/authorize` URL to redirect the browser to (matches supabase-js). */
|
|
37
|
+
authorizeUrl(provider: 'google' | 'apple', redirectTo: string, codeChallenge: string): string;
|
|
38
|
+
/** Exchange the PKCE auth code + verifier for a Supabase session. */
|
|
39
|
+
exchangeCode(code: string, verifier: string): Promise<SupabaseSession>;
|
|
40
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { createHash, randomBytes, randomUUID } from 'node:crypto';
|
|
3
|
+
const FLOW_TTL_MS = 10 * 60 * 1000;
|
|
4
|
+
export class SocialFlowStore {
|
|
5
|
+
flows = new Map();
|
|
6
|
+
/** Store a pending flow and return its opaque id. */
|
|
7
|
+
create(flow) {
|
|
8
|
+
const sid = randomUUID().replace(/-/g, '');
|
|
9
|
+
this.flows.set(sid, { ...flow, expiresAt: Date.now() + FLOW_TTL_MS });
|
|
10
|
+
return sid;
|
|
11
|
+
}
|
|
12
|
+
/** Consume a flow exactly once; undefined if unknown or expired. */
|
|
13
|
+
take(sid) {
|
|
14
|
+
const rec = this.flows.get(sid);
|
|
15
|
+
if (!rec)
|
|
16
|
+
return undefined;
|
|
17
|
+
this.flows.delete(sid);
|
|
18
|
+
if (rec.expiresAt < Date.now())
|
|
19
|
+
return undefined;
|
|
20
|
+
return rec;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export function generatePkce() {
|
|
24
|
+
const verifier = randomBytes(32).toString('base64url'); // 43-char RFC 7636 verifier
|
|
25
|
+
const challenge = createHash('sha256').update(verifier).digest('base64url');
|
|
26
|
+
return { verifier, challenge };
|
|
27
|
+
}
|
|
28
|
+
export class SupabaseOAuthClient {
|
|
29
|
+
url;
|
|
30
|
+
anonKey;
|
|
31
|
+
constructor(url, anonKey) {
|
|
32
|
+
this.url = url;
|
|
33
|
+
this.anonKey = anonKey;
|
|
34
|
+
}
|
|
35
|
+
/** GoTrue `/authorize` URL to redirect the browser to (matches supabase-js). */
|
|
36
|
+
authorizeUrl(provider, redirectTo, codeChallenge) {
|
|
37
|
+
const u = new URL(`${this.url}/auth/v1/authorize`);
|
|
38
|
+
u.searchParams.set('provider', provider);
|
|
39
|
+
u.searchParams.set('redirect_to', redirectTo);
|
|
40
|
+
u.searchParams.set('code_challenge', codeChallenge);
|
|
41
|
+
u.searchParams.set('code_challenge_method', 's256');
|
|
42
|
+
return u.toString();
|
|
43
|
+
}
|
|
44
|
+
/** Exchange the PKCE auth code + verifier for a Supabase session. */
|
|
45
|
+
async exchangeCode(code, verifier) {
|
|
46
|
+
const res = await axios.post(`${this.url}/auth/v1/token?grant_type=pkce`, { auth_code: code, code_verifier: verifier }, {
|
|
47
|
+
headers: { apikey: this.anonKey, 'Content-Type': 'application/json' },
|
|
48
|
+
timeout: 15_000,
|
|
49
|
+
});
|
|
50
|
+
const at = res.data?.access_token;
|
|
51
|
+
const rt = res.data?.refresh_token;
|
|
52
|
+
if (typeof at !== 'string' || typeof rt !== 'string') {
|
|
53
|
+
throw new Error('Supabase did not return a session');
|
|
54
|
+
}
|
|
55
|
+
return { access_token: at, refresh_token: rt };
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=social.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"social.js","sourceRoot":"","sources":["../../src/auth/social.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
CHANGED
|
@@ -16,8 +16,12 @@ export interface Config {
|
|
|
16
16
|
organizationId?: number;
|
|
17
17
|
}
|
|
18
18
|
export declare function loadConfig(): Config;
|
|
19
|
-
export
|
|
19
|
+
export interface HttpConfig {
|
|
20
20
|
apiUrl: string;
|
|
21
|
-
|
|
21
|
+
/** Supabase URL + anon key enable server-side social login (Google/Apple). */
|
|
22
|
+
supabaseUrl?: string;
|
|
23
|
+
supabaseAnonKey?: string;
|
|
24
|
+
}
|
|
25
|
+
export declare function loadHttpConfig(): HttpConfig;
|
|
22
26
|
export declare function validateApiKey(apiKey: string): void;
|
|
23
27
|
export declare function extractApiKey(headers: Record<string, string | string[] | undefined>): string;
|
package/dist/config.js
CHANGED
|
@@ -13,6 +13,8 @@ export function loadConfig() {
|
|
|
13
13
|
export function loadHttpConfig() {
|
|
14
14
|
return {
|
|
15
15
|
apiUrl: process.env.RENT2B_API_URL || DEFAULT_API_URL,
|
|
16
|
+
supabaseUrl: process.env.SUPABASE_URL,
|
|
17
|
+
supabaseAnonKey: process.env.SUPABASE_ANON_KEY,
|
|
16
18
|
};
|
|
17
19
|
}
|
|
18
20
|
export function validateApiKey(apiKey) {
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAkBA,MAAM,eAAe,GAAG,6CAA6C,CAAC;AAEtE,MAAM,UAAU,UAAU;IACxB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAC1C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,CAAC;IACD,cAAc,CAAC,MAAM,CAAC,CAAC;IACvB,OAAO;QACL,MAAM;QACN,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,eAAe;KACtD,CAAC;AACJ,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAkBA,MAAM,eAAe,GAAG,6CAA6C,CAAC;AAEtE,MAAM,UAAU,UAAU;IACxB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAC1C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,CAAC;IACD,cAAc,CAAC,MAAM,CAAC,CAAC;IACvB,OAAO;QACL,MAAM;QACN,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,eAAe;KACtD,CAAC;AACJ,CAAC;AASD,MAAM,UAAU,cAAc;IAC5B,OAAO;QACL,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,eAAe;QACrD,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY;QACrC,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB;KAC/C,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAc;IAC3C,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACpD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAsD;IAClF,MAAM,UAAU,GAAG,OAAO,CAAC,eAAe,CAAuB,CAAC;IAClE,IAAI,UAAU,EAAE,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QACtC,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC7B,CAAC;IACD,MAAM,OAAO,GAAG,OAAO,CAAC,WAAW,CAAuB,CAAC;IAC3D,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,+EAA+E,CAAC,CAAC;AACnG,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,7 @@ import { InMemoryClientsStore, AuthCodeStore } from './auth/stores.js';
|
|
|
9
9
|
import { Rent2bOAuthProvider } from './auth/provider.js';
|
|
10
10
|
import { registerOAuth, xApiKeyToBearer } from './auth/http-oauth.js';
|
|
11
11
|
import { ApiAuthClient } from './auth/api-auth.js';
|
|
12
|
+
import { SupabaseOAuthClient, SocialFlowStore } from './auth/social.js';
|
|
12
13
|
async function main() {
|
|
13
14
|
const args = process.argv.slice(2);
|
|
14
15
|
const useSSE = args.includes('--sse');
|
|
@@ -49,19 +50,24 @@ async function main() {
|
|
|
49
50
|
// their 1h access token expired. Mount a volume at /data on the gateway;
|
|
50
51
|
// if it's absent the store silently falls back to memory.
|
|
51
52
|
const clientsPath = process.env.OAUTH_CLIENTS_PATH || '/data/oauth-clients.json';
|
|
52
|
-
// Social login (Google/Apple)
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
const
|
|
53
|
+
// Social login (Google/Apple): the MCP runs the Supabase PKCE flow itself
|
|
54
|
+
// (server-side code exchange), enabled when SUPABASE_URL + SUPABASE_ANON_KEY
|
|
55
|
+
// are configured. Email/password works regardless.
|
|
56
|
+
const social = httpConfig.supabaseUrl && httpConfig.supabaseAnonKey
|
|
57
|
+
? {
|
|
58
|
+
oauth: new SupabaseOAuthClient(httpConfig.supabaseUrl, httpConfig.supabaseAnonKey),
|
|
59
|
+
store: new SocialFlowStore(),
|
|
60
|
+
}
|
|
61
|
+
: undefined;
|
|
56
62
|
const provider = new Rent2bOAuthProvider({
|
|
57
63
|
codec: createTokenCodec(oauthCfg.encryptionKey),
|
|
58
64
|
clientsStore: new InMemoryClientsStore(clientsPath),
|
|
59
65
|
codeStore: new AuthCodeStore(),
|
|
60
66
|
apiAuth,
|
|
61
67
|
validateKey,
|
|
62
|
-
socialLogin,
|
|
68
|
+
socialLogin: !!social,
|
|
63
69
|
});
|
|
64
|
-
const bearer = registerOAuth(app, { oauthCfg, provider, apiAuth,
|
|
70
|
+
const bearer = registerOAuth(app, { oauthCfg, provider, apiAuth, social });
|
|
65
71
|
// Stateless Streamable HTTP: a fresh MCP server + transport per request, with
|
|
66
72
|
// NO server-side session affinity. tools/list and tool calls work on any
|
|
67
73
|
// request without a prior session, so the client can refresh the tool list
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACxF,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|