diff --git a/.changeset/slimy-ties-approve.md b/.changeset/slimy-ties-approve.md new file mode 100644 index 00000000000..5bc0c276b88 --- /dev/null +++ b/.changeset/slimy-ties-approve.md @@ -0,0 +1,23 @@ +--- +'@clerk/clerk-sdk-node': major +'@clerk/backend': major +'@clerk/nextjs': major +--- + +Changes in exports of `@clerk/backend`: +- Expose the following helpers and enums from `@clerk/backend/jwt`: + ```typescript + import { + decodeJwt, + hasValidSignature, + signJwt, + verifyJwt } from '@clerk/backend/jwt'; + ``` +- Drop the above exports from the top-level api: + ```typescript + // Before + import { decodeJwt, ... } from '@clerk/backend'; + // After + import { decodeJwt, ... } from '@clerk/backend/jwt'; + ``` + Dropping those exports results in also dropping the exports from `gatsby-plugin-clerk`, `@clerk/clerk-sdk-node`, `@clerk/backend`, `@clerk/fastify`, `@clerk/nextjs`, `@clerk/remix` packages. diff --git a/packages/backend/package.json b/packages/backend/package.json index 3d14a27ae8d..97cf6d5e287 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -55,6 +55,16 @@ "default": "./dist/internal.js" } }, + "./jwt": { + "import": { + "types": "./dist/jwt/index.d.ts", + "default": "./dist/jwt/index.mjs" + }, + "require": { + "types": "./dist/jwt/index.d.ts", + "default": "./dist/jwt/index.js" + } + }, "./package.json": "./package.json" }, "main": "./dist/index.js", diff --git a/packages/backend/src/__tests__/exports.test.ts b/packages/backend/src/__tests__/exports.test.ts index 3b21dc4e0c6..218ca170fe9 100644 --- a/packages/backend/src/__tests__/exports.test.ts +++ b/packages/backend/src/__tests__/exports.test.ts @@ -3,6 +3,7 @@ import type QUnit from 'qunit'; import * as errorExports from '../errors'; import * as publicExports from '../index'; import * as internalExports from '../internal'; +import * as jwtExports from '../jwt'; export default (QUnit: QUnit) => { const { module, test } = QUnit; @@ -33,10 +34,6 @@ export default (QUnit: QUnit) => { 'User', 'Verification', 'createClerkClient', - 'decodeJwt', - 'hasValidSignature', - 'signJwt', - 'verifyJwt', 'verifyToken', ]; assert.deepEqual(Object.keys(publicExports).sort(), exportedApiKeys); @@ -74,4 +71,11 @@ export default (QUnit: QUnit) => { assert.deepEqual(Object.keys(internalExports).sort(), exportedApiKeys); }); }); + + module('subpath /jwt exports', () => { + test('should not include a breaking change', assert => { + const exportedApiKeys = ['decodeJwt', 'hasValidSignature', 'signJwt', 'verifyJwt']; + assert.deepEqual(Object.keys(jwtExports).sort(), exportedApiKeys); + }); + }); }; diff --git a/packages/backend/src/tokens/fixtures.ts b/packages/backend/src/fixtures/index.ts similarity index 100% rename from packages/backend/src/tokens/fixtures.ts rename to packages/backend/src/fixtures/index.ts diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index d9bf992bc8f..6247e2ae826 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -8,8 +8,8 @@ import type { CreateAuthenticateRequestOptions } from './tokens/factory'; import { createAuthenticateRequest } from './tokens/factory'; export * from './api/resources'; -export * from './tokens/jwt'; -export * from './tokens/verify'; +export type { VerifyTokenOptions } from './tokens/verify'; +export { verifyToken } from './tokens/verify'; export type ClerkOptions = CreateBackendApiOptions & Partial< diff --git a/packages/backend/src/tokens/jwt/__tests__/assertions.test.ts b/packages/backend/src/jwt/__tests__/assertions.test.ts similarity index 100% rename from packages/backend/src/tokens/jwt/__tests__/assertions.test.ts rename to packages/backend/src/jwt/__tests__/assertions.test.ts diff --git a/packages/backend/src/tokens/jwt/__tests__/cryptoKeys.test.ts b/packages/backend/src/jwt/__tests__/cryptoKeys.test.ts similarity index 100% rename from packages/backend/src/tokens/jwt/__tests__/cryptoKeys.test.ts rename to packages/backend/src/jwt/__tests__/cryptoKeys.test.ts diff --git a/packages/backend/src/tokens/jwt/__tests__/signJwt.test.ts b/packages/backend/src/jwt/__tests__/signJwt.test.ts similarity index 100% rename from packages/backend/src/tokens/jwt/__tests__/signJwt.test.ts rename to packages/backend/src/jwt/__tests__/signJwt.test.ts diff --git a/packages/backend/src/tokens/jwt/__tests__/verifyJwt.test.ts b/packages/backend/src/jwt/__tests__/verifyJwt.test.ts similarity index 100% rename from packages/backend/src/tokens/jwt/__tests__/verifyJwt.test.ts rename to packages/backend/src/jwt/__tests__/verifyJwt.test.ts diff --git a/packages/backend/src/tokens/jwt/algorithms.ts b/packages/backend/src/jwt/algorithms.ts similarity index 100% rename from packages/backend/src/tokens/jwt/algorithms.ts rename to packages/backend/src/jwt/algorithms.ts diff --git a/packages/backend/src/tokens/jwt/assertions.ts b/packages/backend/src/jwt/assertions.ts similarity index 99% rename from packages/backend/src/tokens/jwt/assertions.ts rename to packages/backend/src/jwt/assertions.ts index 4417597895c..f91e9b2636f 100644 --- a/packages/backend/src/tokens/jwt/assertions.ts +++ b/packages/backend/src/jwt/assertions.ts @@ -1,4 +1,4 @@ -import { TokenVerificationError, TokenVerificationErrorAction, TokenVerificationErrorReason } from '../../errors'; +import { TokenVerificationError, TokenVerificationErrorAction, TokenVerificationErrorReason } from '../errors'; import { algs } from './algorithms'; export type IssuerResolver = string | ((iss: string) => boolean); diff --git a/packages/backend/src/tokens/jwt/cryptoKeys.ts b/packages/backend/src/jwt/cryptoKeys.ts similarity index 96% rename from packages/backend/src/tokens/jwt/cryptoKeys.ts rename to packages/backend/src/jwt/cryptoKeys.ts index ae4e3caa1be..fa4200f6c44 100644 --- a/packages/backend/src/tokens/jwt/cryptoKeys.ts +++ b/packages/backend/src/jwt/cryptoKeys.ts @@ -1,6 +1,6 @@ import { isomorphicAtob } from '@clerk/shared/isomorphicAtob'; -import runtime from '../../runtime'; +import runtime from '../runtime'; // https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey#pkcs_8_import function pemToBuffer(secret: string): ArrayBuffer { diff --git a/packages/backend/src/tokens/jwt/index.ts b/packages/backend/src/jwt/index.ts similarity index 100% rename from packages/backend/src/tokens/jwt/index.ts rename to packages/backend/src/jwt/index.ts diff --git a/packages/backend/src/tokens/jwt/signJwt.ts b/packages/backend/src/jwt/signJwt.ts similarity index 95% rename from packages/backend/src/tokens/jwt/signJwt.ts rename to packages/backend/src/jwt/signJwt.ts index 25d2ac08cfa..5f3d2f8ef44 100644 --- a/packages/backend/src/tokens/jwt/signJwt.ts +++ b/packages/backend/src/jwt/signJwt.ts @@ -1,5 +1,5 @@ -import runtime from '../../runtime'; -import { base64url } from '../../util/rfc4648'; +import runtime from '../runtime'; +import { base64url } from '../util/rfc4648'; import { getCryptoAlgorithm } from './algorithms'; import { importKey } from './cryptoKeys'; diff --git a/packages/backend/src/tokens/jwt/verifyJwt.ts b/packages/backend/src/jwt/verifyJwt.ts similarity index 96% rename from packages/backend/src/tokens/jwt/verifyJwt.ts rename to packages/backend/src/jwt/verifyJwt.ts index 4e7c89b3fbc..8e0dc3a81bb 100644 --- a/packages/backend/src/tokens/jwt/verifyJwt.ts +++ b/packages/backend/src/jwt/verifyJwt.ts @@ -1,10 +1,10 @@ import type { Jwt, JwtPayload } from '@clerk/types'; -import { TokenVerificationError, TokenVerificationErrorAction, TokenVerificationErrorReason } from '../../errors'; +import { TokenVerificationError, TokenVerificationErrorAction, TokenVerificationErrorReason } from '../errors'; // DO NOT CHANGE: Runtime needs to be imported as a default export so that we can stub its dependencies with Sinon.js // For more information refer to https://sinonjs.org/how-to/stub-dependency/ -import runtime from '../../runtime'; -import { base64url } from '../../util/rfc4648'; +import runtime from '../runtime'; +import { base64url } from '../util/rfc4648'; import { getCryptoAlgorithm } from './algorithms'; import { assertActivationClaim, diff --git a/packages/backend/src/tokens/__tests__/keys.test.ts b/packages/backend/src/tokens/__tests__/keys.test.ts index eb60a7a2d3e..e1e161d5b5e 100644 --- a/packages/backend/src/tokens/__tests__/keys.test.ts +++ b/packages/backend/src/tokens/__tests__/keys.test.ts @@ -2,8 +2,6 @@ import type QUnit from 'qunit'; import sinon from 'sinon'; import { TokenVerificationError, TokenVerificationErrorAction, TokenVerificationErrorReason } from '../../errors'; -import runtime from '../../runtime'; -import { jsonError, jsonOk } from '../../util/testUtils'; import { mockJwks, mockJwtPayload, @@ -12,7 +10,9 @@ import { mockPEMKey, mockRsaJwk, mockRsaJwkKid, -} from '../fixtures'; +} from '../../fixtures'; +import runtime from '../../runtime'; +import { jsonError, jsonOk } from '../../util/testUtils'; import { loadClerkJWKFromLocal, loadClerkJWKFromRemote } from '../keys'; export default (QUnit: QUnit) => { diff --git a/packages/backend/src/tokens/__tests__/request.test.ts b/packages/backend/src/tokens/__tests__/request.test.ts index a2a03e9ce82..4926c43adfd 100644 --- a/packages/backend/src/tokens/__tests__/request.test.ts +++ b/packages/backend/src/tokens/__tests__/request.test.ts @@ -2,10 +2,10 @@ import type QUnit from 'qunit'; import sinon from 'sinon'; import { TokenVerificationErrorReason } from '../../errors'; +import { mockInvalidSignatureJwt, mockJwks, mockJwt, mockJwtPayload, mockMalformedJwt } from '../../fixtures'; import runtime from '../../runtime'; import { jsonOk } from '../../util/testUtils'; import { AuthErrorReason, type AuthReason, AuthStatus, type RequestState } from '../authStatus'; -import { mockInvalidSignatureJwt, mockJwks, mockJwt, mockJwtPayload, mockMalformedJwt } from '../fixtures'; import type { AuthenticateRequestOptions } from '../request'; import { authenticateRequest, loadOptionsFromHeaders } from '../request'; diff --git a/packages/backend/src/tokens/__tests__/verify.test.ts b/packages/backend/src/tokens/__tests__/verify.test.ts index 97f0d10936c..bd32177b7c9 100644 --- a/packages/backend/src/tokens/__tests__/verify.test.ts +++ b/packages/backend/src/tokens/__tests__/verify.test.ts @@ -1,9 +1,9 @@ import type QUnit from 'qunit'; import sinon from 'sinon'; +import { mockJwks, mockJwt, mockJwtPayload } from '../../fixtures'; import runtime from '../../runtime'; import { jsonOk } from '../../util/testUtils'; -import { mockJwks, mockJwt, mockJwtPayload } from '../fixtures'; import { verifyToken } from '../verify'; export default (QUnit: QUnit) => { diff --git a/packages/backend/src/tokens/handshake.ts b/packages/backend/src/tokens/handshake.ts index fb993ce6ffd..1dfd8b41bb9 100644 --- a/packages/backend/src/tokens/handshake.ts +++ b/packages/backend/src/tokens/handshake.ts @@ -1,6 +1,7 @@ import { TokenVerificationError, TokenVerificationErrorAction, TokenVerificationErrorReason } from '../errors'; -import { decodeJwt, hasValidSignature, type VerifyJwtOptions } from './jwt'; -import { assertHeaderAlgorithm, assertHeaderType } from './jwt/assertions'; +import type { VerifyJwtOptions } from '../jwt'; +import { decodeJwt, hasValidSignature } from '../jwt'; +import { assertHeaderAlgorithm, assertHeaderType } from '../jwt/assertions'; import { loadClerkJWKFromLocal, loadClerkJWKFromRemote } from './keys'; import type { VerifyTokenOptions } from './verify'; diff --git a/packages/backend/src/tokens/request.ts b/packages/backend/src/tokens/request.ts index a6596986133..1dd70b259be 100644 --- a/packages/backend/src/tokens/request.ts +++ b/packages/backend/src/tokens/request.ts @@ -4,13 +4,13 @@ import type { JwtPayload } from '@clerk/types'; import { constants } from '../constants'; import type { TokenCarrier } from '../errors'; import { TokenVerificationError, TokenVerificationErrorReason } from '../errors'; +import { decodeJwt } from '../jwt'; import { assertValidSecretKey } from '../util/assertValidSecretKey'; import { buildRequest, stripAuthorizationHeader } from '../util/IsomorphicRequest'; import { isDevelopmentFromSecretKey } from '../util/shared'; import type { AuthStatusOptionsType, RequestState } from './authStatus'; import { AuthErrorReason, handshake, signedIn, signedOut } from './authStatus'; import { verifyHandshakeToken } from './handshake'; -import { decodeJwt } from './jwt'; import { verifyToken, type VerifyTokenOptions } from './verify'; /** diff --git a/packages/backend/src/tokens/verify.ts b/packages/backend/src/tokens/verify.ts index ae31cce8abb..90d1d716cc0 100644 --- a/packages/backend/src/tokens/verify.ts +++ b/packages/backend/src/tokens/verify.ts @@ -1,8 +1,8 @@ import type { JwtPayload } from '@clerk/types'; import { TokenVerificationError, TokenVerificationErrorAction, TokenVerificationErrorReason } from '../errors'; -import type { VerifyJwtOptions } from './jwt'; -import { decodeJwt, verifyJwt } from './jwt'; +import type { VerifyJwtOptions } from '../jwt'; +import { decodeJwt, verifyJwt } from '../jwt'; import type { LoadClerkJWKFromRemoteOptions } from './keys'; import { loadClerkJWKFromLocal, loadClerkJWKFromRemote } from './keys'; diff --git a/packages/backend/tests/suites.ts b/packages/backend/tests/suites.ts index 40a7dfd84b8..cbb96ac9db2 100644 --- a/packages/backend/tests/suites.ts +++ b/packages/backend/tests/suites.ts @@ -1,21 +1,21 @@ // Import all suites // TODO: Automate this step using dynamic imports -import authObjectsTest from './dist/tokens/__tests__/authObjects.test.js'; -import cryptoKeysTest from './dist/tokens/jwt/__tests__/cryptoKeys.test.js'; import exportsTest from './dist/__tests__/exports.test.js'; +import redirectTest from './dist/__tests__/redirections.test.js'; +import utilsTest from './dist/__tests__/utils.test.js'; import factoryTest from './dist/api/__tests__/factory.test.js'; -import jwtAssertionsTest from './dist/tokens/jwt/__tests__/assertions.test.js'; +import jwtAssertionsTest from './dist/jwt/__tests__/assertions.test.js'; +import cryptoKeysTest from './dist/jwt/__tests__/cryptoKeys.test.js'; +import signJwtTest from './dist/jwt/__tests__/signJwt.test.js'; +import verifyJwtTest from './dist/jwt/__tests__/verifyJwt.test.js'; +import authObjectsTest from './dist/tokens/__tests__/authObjects.test.js'; +import tokenFactoryTest from './dist/tokens/__tests__/factory.test.js'; import keysTest from './dist/tokens/__tests__/keys.test.js'; -import pathTest from './dist/util/__tests__/path.test.js'; -import redirectTest from './dist/__tests__/redirections.test.js'; import requestTest from './dist/tokens/__tests__/request.test.js'; -import signJwtTest from './dist/tokens/jwt/__tests__/signJwt.test.js'; -import tokenFactoryTest from './dist/tokens/__tests__/factory.test.js'; -import utilRequestTest from './dist/util/__tests__/request.test.js'; -import utilsTest from './dist/__tests__/utils.test.js'; -import verifyJwtTest from './dist/tokens/jwt/__tests__/verifyJwt.test.js'; import verifyTest from './dist/tokens/__tests__/verify.test.js'; +import pathTest from './dist/util/__tests__/path.test.js'; +import utilRequestTest from './dist/util/__tests__/request.test.js'; // Add them to the suite array const suites = [ diff --git a/packages/backend/tsup.config.ts b/packages/backend/tsup.config.ts index c01a478fc84..ff644ffe2f3 100644 --- a/packages/backend/tsup.config.ts +++ b/packages/backend/tsup.config.ts @@ -10,7 +10,7 @@ export default defineConfig(overrideOptions => { const shouldPublish = !!overrideOptions.env?.publish; const common: Options = { - entry: ['src/index.ts', 'src/errors.ts', 'src/internal.ts'], + entry: ['src/index.ts', 'src/errors.ts', 'src/internal.ts', 'src/jwt/index.ts'], onSuccess: `cpy 'src/runtime/**/*.{mjs,js,cjs}' dist/runtime`, sourcemap: true, define: { diff --git a/packages/nextjs/src/server/getAuth.ts b/packages/nextjs/src/server/getAuth.ts index 63b7d351da2..9f372fde0ce 100644 --- a/packages/nextjs/src/server/getAuth.ts +++ b/packages/nextjs/src/server/getAuth.ts @@ -1,5 +1,4 @@ import type { Organization, Session, User } from '@clerk/backend'; -import { decodeJwt } from '@clerk/backend'; import type { SignedInAuthObject, SignedOutAuthObject } from '@clerk/backend/internal'; import { AuthStatus, @@ -9,6 +8,7 @@ import { signedInAuthObject, signedOutAuthObject, } from '@clerk/backend/internal'; +import { decodeJwt } from '@clerk/backend/jwt'; import { withLogger } from '../utils/debugLogger'; import { API_URL, API_VERSION, SECRET_KEY } from './constants'; diff --git a/packages/sdk-node/src/__tests__/__snapshots__/exports.test.ts.snap b/packages/sdk-node/src/__tests__/__snapshots__/exports.test.ts.snap index 5a123110874..fc8b0ee9659 100644 --- a/packages/sdk-node/src/__tests__/__snapshots__/exports.test.ts.snap +++ b/packages/sdk-node/src/__tests__/__snapshots__/exports.test.ts.snap @@ -30,11 +30,7 @@ exports[`module exports should not change unless explicitly set 1`] = ` "createClerkClient", "createClerkExpressRequireAuth", "createClerkExpressWithAuth", - "decodeJwt", - "hasValidSignature", "requireAuth", - "signJwt", - "verifyJwt", "verifyToken", "withAuth", ]