@decocms/runtime 1.0.0-alpha.28 → 1.0.0-alpha.30

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.
Files changed (2) hide show
  1. package/package.json +2 -2
  2. package/src/oauth.ts +18 -9
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@decocms/runtime",
3
- "version": "1.0.0-alpha.28",
3
+ "version": "1.0.0-alpha.30",
4
4
  "type": "module",
5
5
  "dependencies": {
6
6
  "@cloudflare/workers-types": "^4.20250617.0",
7
7
  "@deco/mcp": "npm:@jsr/deco__mcp@0.5.5",
8
- "@decocms/bindings": "1.0.1-alpha.16",
8
+ "@decocms/bindings": "1.0.1-alpha.17",
9
9
  "@modelcontextprotocol/sdk": "1.20.2",
10
10
  "@ai-sdk/provider": "^2.0.0",
11
11
  "hono": "^4.10.7",
package/src/oauth.ts CHANGED
@@ -65,6 +65,15 @@ interface CodePayload {
65
65
  codeChallengeMethod?: string;
66
66
  }
67
67
 
68
+ const forceHttps = (url: URL) => {
69
+ const isLocal = url.hostname === "localhost" || url.hostname === "127.0.0.1";
70
+ if (!isLocal) {
71
+ // force http if not local
72
+ url.protocol = "https:";
73
+ }
74
+ return url;
75
+ };
76
+
68
77
  /**
69
78
  * Create OAuth endpoint handlers for MCP servers
70
79
  * The MCP server acts as an OAuth Authorization Server proxy
@@ -77,7 +86,7 @@ export function createOAuthHandlers(oauth: OAuthConfig) {
77
86
  * Points to THIS server as the authorization server
78
87
  */
79
88
  const handleProtectedResourceMetadata = (req: Request): Response => {
80
- const url = new URL(req.url);
89
+ const url = forceHttps(new URL(req.url));
81
90
  const resourceUrl = `${url.origin}/mcp`;
82
91
 
83
92
  return Response.json({
@@ -95,7 +104,7 @@ export function createOAuthHandlers(oauth: OAuthConfig) {
95
104
  * Exposes our endpoints for authorization, token exchange, and registration
96
105
  */
97
106
  const handleAuthorizationServerMetadata = (req: Request): Response => {
98
- const url = new URL(req.url);
107
+ const url = forceHttps(new URL(req.url));
99
108
  const baseUrl = url.origin;
100
109
 
101
110
  return Response.json({
@@ -117,7 +126,7 @@ export function createOAuthHandlers(oauth: OAuthConfig) {
117
126
  * Stateless: encodes all needed info in the state parameter
118
127
  */
119
128
  const handleAuthorize = (req: Request): Response => {
120
- const url = new URL(req.url);
129
+ const url = forceHttps(new URL(req.url));
121
130
  const redirectUri = url.searchParams.get("redirect_uri");
122
131
  const responseType = url.searchParams.get("response_type");
123
132
  const clientState = url.searchParams.get("state");
@@ -155,7 +164,7 @@ export function createOAuthHandlers(oauth: OAuthConfig) {
155
164
  const encodedState = encodeState(pendingState);
156
165
 
157
166
  // Build callback URL pointing to our internal callback
158
- const callbackUrl = new URL(`${url.origin}/oauth/callback`);
167
+ const callbackUrl = forceHttps(new URL(`${url.origin}/oauth/callback`));
159
168
  callbackUrl.searchParams.set("state", encodedState);
160
169
 
161
170
  // Get the external authorization URL from the config
@@ -170,7 +179,7 @@ export function createOAuthHandlers(oauth: OAuthConfig) {
170
179
  * Stateless: decodes state to get redirect info, encodes token in code
171
180
  */
172
181
  const handleOAuthCallback = async (req: Request): Promise<Response> => {
173
- const url = new URL(req.url);
182
+ const url = forceHttps(new URL(req.url));
174
183
  const code = url.searchParams.get("code");
175
184
  const encodedState = url.searchParams.get("state");
176
185
  const error = url.searchParams.get("error");
@@ -184,7 +193,7 @@ export function createOAuthHandlers(oauth: OAuthConfig) {
184
193
  const errorDescription =
185
194
  url.searchParams.get("error_description") ?? "Authorization failed";
186
195
  if (pending?.redirectUri) {
187
- const redirectUrl = new URL(pending.redirectUri);
196
+ const redirectUrl = forceHttps(new URL(pending.redirectUri));
188
197
  redirectUrl.searchParams.set("error", error);
189
198
  redirectUrl.searchParams.set("error_description", errorDescription);
190
199
  if (pending.clientState)
@@ -222,7 +231,7 @@ export function createOAuthHandlers(oauth: OAuthConfig) {
222
231
  const ourCode = encodeState(codePayload);
223
232
 
224
233
  // Redirect back to client with our code
225
- const redirectUrl = new URL(pending.redirectUri);
234
+ const redirectUrl = forceHttps(new URL(pending.redirectUri));
226
235
  redirectUrl.searchParams.set("code", ourCode);
227
236
  if (pending.clientState) {
228
237
  redirectUrl.searchParams.set("state", pending.clientState);
@@ -233,7 +242,7 @@ export function createOAuthHandlers(oauth: OAuthConfig) {
233
242
  console.error("OAuth callback error:", err);
234
243
 
235
244
  // Redirect back to client with error
236
- const redirectUrl = new URL(pending.redirectUri);
245
+ const redirectUrl = forceHttps(new URL(pending.redirectUri));
237
246
  redirectUrl.searchParams.set("error", "server_error");
238
247
  redirectUrl.searchParams.set(
239
248
  "error_description",
@@ -445,7 +454,7 @@ export function createOAuthHandlers(oauth: OAuthConfig) {
445
454
  * Per MCP spec: MUST include resource_metadata URL
446
455
  */
447
456
  const createUnauthorizedResponse = (req: Request): Response => {
448
- const url = new URL(req.url);
457
+ const url = forceHttps(new URL(req.url));
449
458
  const resourceMetadataUrl = `${url.origin}/.well-known/oauth-protected-resource`;
450
459
  const wwwAuthenticateValue = `Bearer resource_metadata="${resourceMetadataUrl}", scope="*"`;
451
460