Skip to content

Commit 9aa18fa

Browse files
committed
fix(clerk-sdk-node): Use dummy base url and isomorphicRequest for requestUrl
1 parent 4d0d902 commit 9aa18fa

2 files changed

Lines changed: 19 additions & 35 deletions

File tree

packages/sdk-node/src/__tests__/middleware.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import type { WithAuthProp } from '../types';
77

88
const mockNext = jest.fn();
99

10-
const createRequest = () => ({ url: '/path', cookies: {}, headers: {} } as Request);
10+
const createRequest = () => ({ url: '/path', cookies: {}, headers: { host: 'example.com' } } as Request);
1111

1212
afterEach(() => {
1313
mockNext.mockReset();

packages/sdk-node/src/authenticateRequest.ts

Lines changed: 18 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { RequestState } from '@clerk/backend';
2-
import { constants, createIsomorphicRequest } from '@clerk/backend';
3-
import type { IncomingMessage, ServerResponse } from 'http';
2+
import { buildRequestUrl, constants, createIsomorphicRequest } from '@clerk/backend';
3+
import type { ServerResponse } from 'http';
44

55
import { handleValueOrFn, isHttpOrHttps, isProxyUrlRelative, isValidProxyUrl } from './shared';
66
import type { AuthenticateRequestParams, ClerkClient } from './types';
@@ -39,7 +39,21 @@ export const authenticateRequest = (opts: AuthenticateRequestParams) => {
3939

4040
const env = { ...loadApiEnv(), ...loadClientEnv() };
4141

42-
const requestUrl = getRequestUrl(req);
42+
const isomorphicRequest = createIsomorphicRequest((Request, Headers) => {
43+
const headers = Object.keys(req.headers).reduce((acc, key) => Object.assign(acc, { [key]: req?.headers[key] }), {});
44+
45+
// @ts-ignore Optimistic attempt to get the protocol in case
46+
// req extends IncomingMessage in a useful way. No guarantee
47+
// it'll work.
48+
const protocol = req.connection?.encrypted ? 'https' : 'http';
49+
const dummyOriginReqUrl = new URL(req.url || '', `${protocol}://clerk-dummy`);
50+
return new Request(dummyOriginReqUrl, {
51+
method: req.method,
52+
headers: new Headers(headers),
53+
});
54+
});
55+
56+
const requestUrl = buildRequestUrl(isomorphicRequest);
4357
const isSatellite = handleValueOrFn(options?.isSatellite, requestUrl, env.isSatellite);
4458
const domain = handleValueOrFn(options?.domain, requestUrl) || env.domain;
4559
const signInUrl = options?.signInUrl || env.signInUrl;
@@ -68,16 +82,7 @@ export const authenticateRequest = (opts: AuthenticateRequestParams) => {
6882
isSatellite,
6983
domain,
7084
signInUrl,
71-
request: createIsomorphicRequest((Request, Headers) => {
72-
const headers = Object.keys(req.headers).reduce(
73-
(acc, key) => Object.assign(acc, { [key]: req?.headers[key] }),
74-
{},
75-
);
76-
return new Request(requestUrl, {
77-
method: req.method,
78-
headers: new Headers(headers),
79-
});
80-
}),
85+
request: isomorphicRequest,
8186
});
8287
};
8388
export const handleUnknownCase = (res: ServerResponse, requestState: RequestState) => {
@@ -103,25 +108,6 @@ export const decorateResponseWithObservabilityHeaders = (res: ServerResponse, re
103108
const isDevelopmentFromApiKey = (apiKey: string): boolean =>
104109
apiKey.startsWith('test_') || apiKey.startsWith('sk_test_');
105110

106-
const getRequestUrl = (req: IncomingMessage): URL => {
107-
return new URL(req.url as string, `${getRequestProto(req)}://${req.headers.host}`);
108-
};
109-
110-
const getRequestProto = (req: IncomingMessage): string => {
111-
// @ts-ignore Optimistic attempt to get the protocol in case
112-
// req extends IncomingMessage in a useful way. No guarantee
113-
// it'll work.
114-
const mightWork = req.connection?.encrypted ? 'https' : 'http';
115-
// The x-forwarded-proto header takes precedence.
116-
const proto = (req.headers[constants.Headers.ForwardedProto] as string) || mightWork;
117-
if (!proto) {
118-
throw new Error(missingProto);
119-
}
120-
// Sometimes the x-forwarded-proto header does not come as a
121-
// single value.
122-
return proto.split(',')[0].trim();
123-
};
124-
125111
const absoluteProxyUrl = (relativeOrAbsoluteUrl: string, baseUrl: string): string => {
126112
if (!relativeOrAbsoluteUrl || !isValidProxyUrl(relativeOrAbsoluteUrl) || !isProxyUrlRelative(relativeOrAbsoluteUrl)) {
127113
return relativeOrAbsoluteUrl;
@@ -134,5 +120,3 @@ const satelliteAndMissingProxyUrlAndDomain =
134120
const satelliteAndMissingSignInUrl = `
135121
Invalid signInUrl. A satellite application requires a signInUrl for development instances.
136122
Check if signInUrl is missing from your configuration or if it is not an absolute URL.`;
137-
const missingProto =
138-
"Cannot determine the request protocol. Please ensure you've set the X-Forwarded-Proto header with the request protocol (http or https).";

0 commit comments

Comments
 (0)