Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(nextjs,shared): Improve CLERK_API_URL default value #1955

Merged
merged 2 commits into from
Nov 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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';
LekoArts marked this conversation as resolved.
Show resolved Hide resolved
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'];
Loading