Skip to content

Commit

Permalink
feat(nextjs,shared): Improve CLERK_API_URL default value (#1955)
Browse files Browse the repository at this point in the history
* feat(nextjs,shared,remix,gatsby-plugin-clerk): Improve CLERK_API_URL default value

* feat(fastify): Improve CLERK_API_URL default value
  • Loading branch information
desiprisg authored Nov 3, 2023
1 parent d683bee commit 7644b74
Show file tree
Hide file tree
Showing 17 changed files with 109 additions and 88 deletions.
9 changes: 9 additions & 0 deletions .changeset/rude-jobs-yawn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@clerk/nextjs': patch
'@clerk/remix': patch
'gatsby-plugin-clerk': patch
'@clerk/shared': patch
'@clerk/fastify': patch
---

Improve the default value for `CLERK_API_URL` by utilizing the publishable key to differentiate between local, staging and prod environments.
41 changes: 3 additions & 38 deletions packages/clerk-js/src/utils/url.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { camelToSnake, createDevOrStagingUrlCache } from '@clerk/shared';
import { globs } from '@clerk/shared/globs';
import { createDevOrStagingUrlCache } from '@clerk/shared/keys';
import { camelToSnake } from '@clerk/shared/underscore';
import { isCurrentDevAccountPortalOrigin, isLegacyDevAccountPortalOrigin } from '@clerk/shared/url';
import type { SignUpResource } from '@clerk/types';

import { joinPaths } from './path';
Expand All @@ -16,21 +18,6 @@ declare global {
// This is used as a dummy base when we need to invoke "new URL()" but we don't care about the URL origin.
const DUMMY_URL_BASE = 'http://clerk-dummy';

export const DEV_OR_STAGING_SUFFIXES = [
'.lcl.dev',
'.stg.dev',
'.lclstage.dev',
'.stgstage.dev',
'.dev.lclclerk.com',
'.stg.lclclerk.com',
'.accounts.lclclerk.com',
'accountsstage.dev',
'accounts.dev',
];

export const LEGACY_DEV_SUFFIXES = ['.lcl.dev', '.lclstage.dev', '.lclclerk.com'];
export const CURRENT_DEV_SUFFIXES = ['.accounts.dev', '.accountsstage.dev', '.accounts.lclclerk.com'];

const BANNED_URI_PROTOCOLS = ['javascript:'] as const;

const { isDevOrStagingUrl } = createDevOrStagingUrlCache();
Expand All @@ -52,28 +39,6 @@ export function isDevAccountPortalOrigin(hostname: string = window.location.host
return res;
}

// Returns true for hosts such as:
// * accounts.foo.bar-13.lcl.dev
// * accounts.foo.bar-13.lclstage.dev
// * accounts.foo.bar-13.dev.lclclerk.com
function isLegacyDevAccountPortalOrigin(host: string): boolean {
return LEGACY_DEV_SUFFIXES.some(legacyDevSuffix => {
return host.startsWith('accounts.') && host.endsWith(legacyDevSuffix);
});
}

// Returns true for hosts such as:
// * foo-bar-13.accounts.dev
// * foo-bar-13.accountsstage.dev
// * foo-bar-13.accounts.lclclerk.com
// But false for:
// * foo-bar-13.clerk.accounts.lclclerk.com
function isCurrentDevAccountPortalOrigin(host: string): boolean {
return CURRENT_DEV_SUFFIXES.some(currentDevSuffix => {
return host.endsWith(currentDevSuffix) && !host.endsWith('.clerk' + currentDevSuffix);
});
}

export function getETLDPlusOneFromFrontendApi(frontendApi: string): string {
return frontendApi.replace('clerk.', '');
}
Expand Down
3 changes: 2 additions & 1 deletion packages/fastify/src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { constants } from '@clerk/backend';
import { apiUrlFromPublishableKey } from '@clerk/shared/apiUrlFromPublishableKey';

export const API_URL = process.env.CLERK_API_URL || 'https://api.clerk.com';
export const API_VERSION = process.env.CLERK_API_VERSION || 'v1';
export const SECRET_KEY = process.env.CLERK_SECRET_KEY || '';
export const PUBLISHABLE_KEY = process.env.CLERK_PUBLISHABLE_KEY || '';
export const API_URL = process.env.CLERK_API_URL || apiUrlFromPublishableKey(PUBLISHABLE_KEY);
export const JWT_KEY = process.env.CLERK_JWT_KEY || '';

export const { Cookies, Headers } = constants;
6 changes: 4 additions & 2 deletions packages/gatsby-plugin-clerk/src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
export const API_URL = process.env.CLERK_API_URL || 'https://api.clerk.com';
import { apiUrlFromPublishableKey } from '@clerk/shared/apiUrlFromPublishableKey';

export const PUBLISHABLE_KEY = process.env.GATSBY_CLERK_PUBLISHABLE_KEY || '';
export const API_URL = process.env.CLERK_API_URL || apiUrlFromPublishableKey(PUBLISHABLE_KEY);
export const API_VERSION = process.env.CLERK_API_VERSION || 'v1';
export const SECRET_KEY = process.env.CLERK_SECRET_KEY || '';
export const PUBLISHABLE_KEY = process.env.GATSBY_CLERK_PUBLISHABLE_KEY || '';

export const CLERK_JS = process.env.GATSBY_CLERK_JS;
export const PROXY_URL = process.env.GATSBY_CLERK_PROXY_URL;
3 changes: 2 additions & 1 deletion packages/nextjs/src/server/constants.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { apiUrlFromPublishableKey } from '@clerk/shared/apiUrlFromPublishableKey';
import { isTruthy } from '@clerk/shared/underscore';

export const CLERK_JS_VERSION = process.env.NEXT_PUBLIC_CLERK_JS_VERSION || '';
export const CLERK_JS_URL = process.env.NEXT_PUBLIC_CLERK_JS || '';
export const API_URL = process.env.CLERK_API_URL || 'https://api.clerk.com';
export const API_VERSION = process.env.CLERK_API_VERSION || 'v1';
export const SECRET_KEY = process.env.CLERK_SECRET_KEY || '';
export const PUBLISHABLE_KEY = process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY || '';
export const API_URL = process.env.CLERK_API_URL || apiUrlFromPublishableKey(PUBLISHABLE_KEY);
export const DOMAIN = process.env.NEXT_PUBLIC_CLERK_DOMAIN || '';
export const PROXY_URL = process.env.NEXT_PUBLIC_CLERK_PROXY_URL || '';
export const IS_SATELLITE = isTruthy(process.env.NEXT_PUBLIC_CLERK_IS_SATELLITE) || false;
Expand Down
28 changes: 1 addition & 27 deletions packages/nextjs/src/server/url.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
// TODO: This is a partial duplicate of part of packages/clerk-js/src/utils/url.ts
// TODO: To be removed when we can extract this utility to @clerk/shared

export const LEGACY_DEV_SUFFIXES = ['.lcl.dev', '.lclstage.dev', '.lclclerk.com'];
export const CURRENT_DEV_SUFFIXES = ['.accounts.dev', '.accountsstage.dev', '.accounts.lclclerk.com'];
import { isCurrentDevAccountPortalOrigin, isLegacyDevAccountPortalOrigin } from '@clerk/shared/url';

const accountPortalCache = new Map<string, boolean>();

Expand All @@ -20,25 +16,3 @@ export function isDevAccountPortalOrigin(hostname: string): boolean {

return res;
}

// Returns true for hosts such as:
// * accounts.foo.bar-13.lcl.dev
// * accounts.foo.bar-13.lclstage.dev
// * accounts.foo.bar-13.dev.lclclerk.com
function isLegacyDevAccountPortalOrigin(host: string): boolean {
return LEGACY_DEV_SUFFIXES.some(legacyDevSuffix => {
return host.startsWith('accounts.') && host.endsWith(legacyDevSuffix);
});
}

// Returns true for hosts such as:
// * foo-bar-13.accounts.dev
// * foo-bar-13.accountsstage.dev
// * foo-bar-13.accounts.lclclerk.com
// But false for:
// * foo-bar-13.clerk.accounts.lclclerk.com
function isCurrentDevAccountPortalOrigin(host: string): boolean {
return CURRENT_DEV_SUFFIXES.some(currentDevSuffix => {
return host.endsWith(currentDevSuffix) && !host.endsWith('.clerk' + currentDevSuffix);
});
}
3 changes: 2 additions & 1 deletion packages/remix/src/ssr/authenticateRequest.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { RequestState } from '@clerk/backend';
import { buildRequestUrl, Clerk } from '@clerk/backend';
import { apiUrlFromPublishableKey } from '@clerk/shared/apiUrlFromPublishableKey';
import { handleValueOrFn } from '@clerk/shared/handleValueOrFn';
import { isDevelopmentFromApiKey } from '@clerk/shared/keys';
import { isHttpOrHttps, isProxyUrlRelative } from '@clerk/shared/proxy';
Expand Down Expand Up @@ -36,7 +37,7 @@ export function authenticateRequest(args: LoaderFunctionArgs, opts: RootAuthLoad

const jwtKey = opts.jwtKey || getEnvVariable('CLERK_JWT_KEY', context);

const apiUrl = getEnvVariable('CLERK_API_URL', context);
const apiUrl = getEnvVariable('CLERK_API_URL', context) || apiUrlFromPublishableKey(publishableKey);

const domain = handleValueOrFn(opts.domain, new URL(request.url)) || getEnvVariable('CLERK_DOMAIN', context) || '';

Expand Down
4 changes: 3 additions & 1 deletion packages/shared/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,6 @@ poller
proxy
underscore
url
react
react
constants
apiUrlFromPublishableKey
4 changes: 3 additions & 1 deletion packages/shared/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@
"proxy",
"underscore",
"url",
"react"
"react",
"constants",
"apiUrlFromPublishableKey"
],
"scripts": {
"build": "tsup",
Expand Down
18 changes: 18 additions & 0 deletions packages/shared/src/__tests__/apiUrlFromPublishableKey.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { apiUrlFromPublishableKey } from '../apiUrlFromPublishableKey';

describe('apiUrlFromPublishableKey', () => {
test('returns the prod api url when given a prod publishable key', async () => {
const apiUrl = apiUrlFromPublishableKey('pk_test_bWFueS1zZWFsLTkwLmNsZXJrLmFjY291bnRzLmRldiQ');
expect(apiUrl).toBe('https://api.clerk.com');
});

test('returns the prod api url when given a staging publishable key', async () => {
const apiUrl = apiUrlFromPublishableKey('pk_test_aW1tdW5lLWhhd2stNjUuY2xlcmsuYWNjb3VudHNzdGFnZS5kZXYk');
expect(apiUrl).toBe('https://api.clerkstage.dev');
});

test('returns the prod api url when given a local publishable key', async () => {
const apiUrl = apiUrlFromPublishableKey('pk_test_cGF0aWVudC1nb29zZS01LmNsZXJrLmFjY291bnRzLmxjbGNsZXJrLmNvbSQ');
expect(apiUrl).toBe('https://api.lclclerk.com');
});
});
13 changes: 13 additions & 0 deletions packages/shared/src/apiUrlFromPublishableKey.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { LOCAL_API_URL, LOCAL_ENV_SUFFIXES, PROD_API_URL, STAGING_API_URL, STAGING_ENV_SUFFIXES } from './constants';
import { parsePublishableKey } from './keys';

export const apiUrlFromPublishableKey = (publishableKey: string) => {
const frontendApi = parsePublishableKey(publishableKey)?.frontendApi;
if (LOCAL_ENV_SUFFIXES.some(suffix => frontendApi?.endsWith(suffix))) {
return LOCAL_API_URL;
}
if (STAGING_ENV_SUFFIXES.some(suffix => frontendApi?.endsWith(suffix))) {
return STAGING_API_URL;
}
return PROD_API_URL;
};
18 changes: 18 additions & 0 deletions packages/shared/src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export const LEGACY_DEV_INSTANCE_SUFFIXES = ['.lcl.dev', '.lclstage.dev', '.lclclerk.com'];
export const CURRENT_DEV_INSTANCE_SUFFIXES = ['.accounts.dev', '.accountsstage.dev', '.accounts.lclclerk.com'];
export const DEV_OR_STAGING_SUFFIXES = [
'.lcl.dev',
'.stg.dev',
'.lclstage.dev',
'.stgstage.dev',
'.dev.lclclerk.com',
'.stg.lclclerk.com',
'.accounts.lclclerk.com',
'accountsstage.dev',
'accounts.dev',
];
export const LOCAL_ENV_SUFFIXES = ['.lcl.dev', 'lclstage.dev', '.lclclerk.com', '.accounts.lclclerk.com'];
export const STAGING_ENV_SUFFIXES = ['.accountsstage.dev'];
export const LOCAL_API_URL = 'https://api.lclclerk.com';
export const STAGING_API_URL = 'https://api.clerkstage.dev';
export const PROD_API_URL = 'https://api.clerk.com';
4 changes: 3 additions & 1 deletion packages/shared/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@

export * from './utils';

export { createWorkerTimers } from './workerTimers';
export { apiUrlFromPublishableKey } from './apiUrlFromPublishableKey';
export * from './browser';
export { callWithRetry } from './callWithRetry';
export * from './color';
export * from './constants';
export * from './date';
export * from './deprecated';
export * from './error';
Expand All @@ -27,3 +28,4 @@ export * from './poller';
export * from './proxy';
export * from './underscore';
export * from './url';
export { createWorkerTimers } from './workerTimers';
14 changes: 1 addition & 13 deletions packages/shared/src/keys.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { PublishableKey } from '@clerk/types';

import { DEV_OR_STAGING_SUFFIXES } from './constants';
import { isomorphicAtob } from './isomorphicAtob';

const PUBLISHABLE_KEY_LIVE_PREFIX = 'pk_live_';
Expand Down Expand Up @@ -55,19 +56,6 @@ export function isLegacyFrontendApiKey(key: string) {
}

export function createDevOrStagingUrlCache() {
// TODO: Check if we can merge it with `./instance.ts#isStaging()`
const DEV_OR_STAGING_SUFFIXES = [
'.lcl.dev',
'.stg.dev',
'.lclstage.dev',
'.stgstage.dev',
'.dev.lclclerk.com',
'.stg.lclclerk.com',
'.accounts.lclclerk.com',
'accountsstage.dev',
'accounts.dev',
];

const devOrStagingUrlCache = new Map<string, boolean>();

return {
Expand Down
23 changes: 23 additions & 0 deletions packages/shared/src/url.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { CURRENT_DEV_INSTANCE_SUFFIXES, LEGACY_DEV_INSTANCE_SUFFIXES } from './constants';
import { isStaging } from './utils/instance';

export function parseSearchParams(queryString = ''): URLSearchParams {
Expand Down Expand Up @@ -64,3 +65,25 @@ export const getScriptUrl = (
const major = getClerkJsMajorVersionOrTag(frontendApi, pkgVersion);
return `https://${noSchemeFrontendApi}/npm/@clerk/clerk-js@${clerkJSVersion || major}/dist/clerk.browser.js`;
};

// Returns true for hosts such as:
// * accounts.foo.bar-13.lcl.dev
// * accounts.foo.bar-13.lclstage.dev
// * accounts.foo.bar-13.dev.lclclerk.com
export function isLegacyDevAccountPortalOrigin(host: string): boolean {
return LEGACY_DEV_INSTANCE_SUFFIXES.some(legacyDevSuffix => {
return host.startsWith('accounts.') && host.endsWith(legacyDevSuffix);
});
}

// Returns true for hosts such as:
// * foo-bar-13.accounts.dev
// * foo-bar-13.accountsstage.dev
// * foo-bar-13.accounts.lclclerk.com
// But false for:
// * foo-bar-13.clerk.accounts.lclclerk.com
export function isCurrentDevAccountPortalOrigin(host: string): boolean {
return CURRENT_DEV_INSTANCE_SUFFIXES.some(currentDevSuffix => {
return host.endsWith(currentDevSuffix) && !host.endsWith('.clerk' + currentDevSuffix);
});
}
4 changes: 2 additions & 2 deletions packages/shared/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export * from './createDeferredPromise';
export { isStaging } from './instance';
export { logErrorInDevMode } from './logErrorInDevMode';
export { noop } from './noop';
export * from './runtimeEnvironment';
export * from './runWithExponentialBackOff';
export { logErrorInDevMode } from './logErrorInDevMode';
export * from './runtimeEnvironment';
2 changes: 2 additions & 0 deletions packages/shared/subpaths.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export const subpathNames = [
'proxy',
'underscore',
'url',
'constants',
'apiUrlFromPublishableKey',
];

export const subpathFoldersBarrel = ['react'];

0 comments on commit 7644b74

Please sign in to comment.