Skip to content

Commit ac06bf2

Browse files
colinclerknikosdouvlisbrkalow
authored
Client handshake tests (#2265)
* Test suite start * feat(backend,nextjs,utils): Fix jest * first test * Fix bug in jwks cache for multiple runtime keys * Add all the tests, including many failing * Add all the tests, including many failing * fix(shared): Correctly construct proxy URL --------- Co-authored-by: Nikos Douvlis <[email protected]> Co-authored-by: Bryce Kalow <[email protected]>
1 parent 5c88498 commit ac06bf2

File tree

11 files changed

+821
-62
lines changed

11 files changed

+821
-62
lines changed

handshake.test.ts

Lines changed: 615 additions & 0 deletions
Large diffs are not rendered by default.

handshakeTestConfigs.ts

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
// @ts-ignore ignore types
2+
import * as jwt from 'jsonwebtoken';
3+
// @ts-ignore ignore types
4+
import * as uuid from 'uuid';
5+
6+
const rsaPairs = {
7+
a: {
8+
private: `-----BEGIN RSA PRIVATE KEY-----
9+
MIIEowIBAAKCAQEAlRVgJiQJ0nfuctIVSLnFJlAC76YPKly8Y5xrY36ADo472G1w
10+
FpeiykQRyDdGOwrkJBEVmLpAybV4yTgQFpQ0A4YzeDlKKkOxBhCmuANZXluAm2MW
11+
3ehNAm0svievMfKtG6UjjYz6v67U9Om/oMt1ehsOmR8MrDYvs3Wy+dxYpZaxyn6w
12+
ajL7GkICHxc8cGsI/MBZr9jKtKyzFY++r8TQKAJwn9TcSQljRivomz1wQvjtdLnq
13+
ZSLP3BFQB7e7DuM6SBsodIHhkVEVK2EaGVLOY+ifAITt7MqEcvast14AP0rICBSq
14+
vbQQjZuwLgIrlJgqvJ4YBRfIaIx/qQzs0+eFtwIDAQABAoIBAD1H4xTqfWsZR1fF
15+
SWBylDqSaxKNRPCZ3ApqEq58IjFZf/oPyiJPRGg2IMUXC3RbnrnAmAsGjHkdcj/s
16+
HpjZZKQKNv/1NKo41vxyPcWoAsVJgYzd51liEr2rmNe1QkuawFN7xyh5Sd0fBYSC
17+
zPVQjMKbep2waKolP+hZui8AxyORLtu6aUQawaCdWFyiyHtqEnlcb/YSTtGl/3W/
18+
/LqYyv60dG0QdcAO37MAE42vp3R4GGcJelsFo/lxSKg+KiLn7NdsNr7bCJrqbVXz
19+
93Fu5jgHQD9+BeVyvHJ/R2yg+utYEvIMiFvwX7z4MLh9PsWJbf9vbDNlw9ErWpf5
20+
r1xUiqECgYEA/lLJP+qla0vd+ocYNe3ufOG4kaUFsrqRoChiS1JxwQr/WGTmV8sT
21+
ZyTPwyxnsHtbzn4lwuI6CpAeyvd9O6G3FfTzUqsyPaknsGlymf8LEwL4AVo0BVY0
22+
YGodRnDISBBU/yPQ2kvq6c72ouq5cQxWF45f8Z/Z+fFDjuHG6Q44hYcCgYEAlhD6
23+
sm8wTWVklMAxOnhQJoseWQ1vcl6VCxRVv4QBiX9CQm/4ANVOWun4KRC5qqTdoNHc
24+
RyuiWpZVgGblqUu4sWSQgi3CZyyLbHOJ9wTPTeo0oDVaFa9MMwS8rq35HXjpgREz
25+
JtTRi6c9WVsjBygYiE5IYO0FGbEjI9qIiD5CClECgYA+wtVRRamu0dkk0yPhYycg
26+
gF+Y6Z1/XtVDLdQb/GuAFSOwf63sanwOTyJKavHntnmQesb80fE63BgNRIgOKDlT
27+
XNCTTRYn60+VFGCoqizkcy4av1TpID3qsSUqVfjG9+jR0dffly6Qpnds+vnqcP3p
28+
8EOzEByttqFSaFs69jxyjwKBgFCQbQa+isACXy08wTESxnTq2zAT9nEANiPsltxq
29+
kiivGXNxiUNpQNeuJHxnbkYenJ1qDUhoNJFNhDmbBFEPReh2hN5ekq+xSmi+3qKv
30+
AlxiED6yZdqecdoyANoGrGcWMsYH5d5DAvxmnJkMRJHjBMiovlLK7KIOZz8oY4RB
31+
aFMBAoGBAJ8UoGHwz7AdOLAldGY3c0HzaH1NaGrZoocSH19XI3ZYr8Qvl2XUww9G
32+
UC1OG4e2PtZ8PINQGIYPacUaab5Yg1tOmxBoAx4gUkpgyjtSm2ZPd4EUVOdylU3E
33+
aFa08+0FF7mqqJTgz5XlvHMrCcUTsJ9u+e05rr1G1PHsATuuMD9m
34+
-----END RSA PRIVATE KEY-----`,
35+
public: {
36+
kty: 'RSA',
37+
n: 'lRVgJiQJ0nfuctIVSLnFJlAC76YPKly8Y5xrY36ADo472G1wFpeiykQRyDdGOwrkJBEVmLpAybV4yTgQFpQ0A4YzeDlKKkOxBhCmuANZXluAm2MW3ehNAm0svievMfKtG6UjjYz6v67U9Om_oMt1ehsOmR8MrDYvs3Wy-dxYpZaxyn6wajL7GkICHxc8cGsI_MBZr9jKtKyzFY--r8TQKAJwn9TcSQljRivomz1wQvjtdLnqZSLP3BFQB7e7DuM6SBsodIHhkVEVK2EaGVLOY-ifAITt7MqEcvast14AP0rICBSqvbQQjZuwLgIrlJgqvJ4YBRfIaIx_qQzs0-eFtw',
38+
e: 'AQAB',
39+
},
40+
},
41+
b: {
42+
private: `-----BEGIN RSA PRIVATE KEY-----
43+
MIIEowIBAAKCAQEAt9zSYl1hFhFKXvv8uJcT2X15iOqi1mTtxqVxNDnzPQSj1RSa
44+
Jryjhkzpyd16c+PDo+FFtMgZTUv6Z2hr5QYMuAjlsM+apHmfE8MRMQRQHXNF0+sE
45+
Bd1241W0mL7fId2ZChaGgufFOGFl2Obby56FH4Z86lCFi7Z4Ow7TBSpVSN598OKH
46+
oVKwbYOVPKtmWBar0JeCPVpng4Ntx7kvuHGdFSoJ8z8+Uy5ybLlk1qSlQ5lsymfW
47+
hxs0C9j7/x/h24n9jUbq51pzx2URcsEi0Wbuv26Ba0Q4v1ySl0I6IM5Xemwrzjo1
48+
H6kz6IYldqPtTwkzhJSnJvJFzKJZn3hH9N+rGwIDAQABAoIBAGLGdx/xGp9IWrP8
49+
nCBuyXMmPYyYwTJ8tmDpsI9mMo6tV3a5wrbc0NztpQuVuJtZ2VjJRTGB7lXgY336
50+
UzyOq3aTERKT9Xg2/ocXXL0AnCm2K+VVdKvR9nTbLlKA+E6xRe5te4YIDaPkb1q/
51+
a4VQfCQblDAtYhFUzfKsXCGCRJ8IPlhZxiA9RHfQTmQUSoBW+12IovyMdMxVLoPT
52+
qjdnwL1TS3iARim+eV+buHW+8Drn8eldeSFoTJd0B9eRf7pMpRH/X8G7X0YYdDjF
53+
ADWI770CQj45QQeuVsZYIuONIPmzai4nGiNQ85v+Yy0L47lYUp5XsDvwYO5tMCQK
54+
v1og8cECgYEA7zIfBWM1AIY763FGJ6F5ym41A4i7WSRaWusfQx6fOdGTyHJ3hXu9
55+
+1kQS97IKElJ1V7oK69dJGxq+aupsd/AaRJb4oVZCBSby4Fo6VeJoKyJSdNSCks6
56+
tonT3hGUsJO1ER2ItWcgiCxgGY+vrK0rkacX/VgNZKGIjlGv8pQUpaUCgYEAxMeL
57+
2jyx+5odGM51e/1G4Vn6t+ffNNC/03NbwZeJ93+0NPgdagIo1kErZQrFPEfoExOr
58+
KMkwnAsnR/xfn4X21voK1pUc7VhzzoODb8l9LA9kB7efWtRZA79gcsbOH5wNkp9Z
59+
i76AtaVU/p1grFKNcnes1lbFfcRUnO880g5dsb8CgYBacuuEEAWk0x2pZEYRCmCR
60+
iacGVRfzF2oLY0mJCfVP2c42SAKmOSqX9w/QgMfTZBNFWgQVMNTZxx2Ul7Mtjdym
61+
XsjcGWyXP6PCCodvZSin11Z60iv9tIDZMbkqCh/dvZ0EgdSGNB77HzyfrdPSShFl
62+
nHfX1woJeYO3vW/5HMHJ+QKBgQCNema7pq3Ulq5a2n2vgp9GgJn5RXW+lGOG1Mbg
63+
vmJMlv1qpAUJ5bmUqdBYWlEKkSxzIs4JifUwC/jXEcVyfS/GyommVBkzMEg672U9
64+
pyEe34Xs4oFpHYlOX3cprnQeV+WOSJFqHrKNZuxgD6ik3MmjxhV3GXXugYzQNFWH
65+
NRr6IwKBgH9aN5mY4fcVL76mMEVZ5BIHE+JpPMZ6OOamOHAiA5jrWRX4aRMICq3t
66+
cKVfcj/M4dyBuRV5EW1y1m2QhRECFPSKpScykpD9nyCb+XqbMSLH+f+j1BGfLKWl
67+
t5o8u/dlwJ1fGGday48gs/hA4V/F9zDjecNkYWUB/wUwVStqZljn
68+
-----END RSA PRIVATE KEY-----`,
69+
public: {
70+
kty: 'RSA',
71+
n: 't9zSYl1hFhFKXvv8uJcT2X15iOqi1mTtxqVxNDnzPQSj1RSaJryjhkzpyd16c-PDo-FFtMgZTUv6Z2hr5QYMuAjlsM-apHmfE8MRMQRQHXNF0-sEBd1241W0mL7fId2ZChaGgufFOGFl2Obby56FH4Z86lCFi7Z4Ow7TBSpVSN598OKHoVKwbYOVPKtmWBar0JeCPVpng4Ntx7kvuHGdFSoJ8z8-Uy5ybLlk1qSlQ5lsymfWhxs0C9j7_x_h24n9jUbq51pzx2URcsEi0Wbuv26Ba0Q4v1ySl0I6IM5Xemwrzjo1H6kz6IYldqPtTwkzhJSnJvJFzKJZn3hH9N-rGw',
72+
e: 'AQAB',
73+
},
74+
},
75+
};
76+
77+
const allConfigs: any = [];
78+
79+
export function generateConfig({ mode, matchedKeys = true }: { mode: 'test' | 'live'; matchedKeys?: boolean }) {
80+
const ins_id = uuid.v4();
81+
const pkHost = `clerk.${uuid.v4()}.com`;
82+
const pk = `pk_${mode}_${btoa(`${pkHost}$`)}`;
83+
const sk = `sk_${mode}_${uuid.v4()}`;
84+
const rsa = matchedKeys
85+
? rsaPairs.a
86+
: {
87+
private: rsaPairs.a.private,
88+
public: rsaPairs.b.public,
89+
};
90+
const jwks = {
91+
keys: [
92+
{
93+
...rsa.public,
94+
kid: ins_id,
95+
use: 'sig',
96+
alg: 'RS256',
97+
},
98+
],
99+
};
100+
101+
type Claims = {
102+
sub: string;
103+
iat: number;
104+
exp: number;
105+
nbf: number;
106+
};
107+
const generateToken = ({ state }: { state: 'active' | 'expired' | 'early' }) => {
108+
let claims = { sub: 'user_12345' } as Claims;
109+
110+
const now = Math.floor(Date.now() / 1000);
111+
if (state === 'active') {
112+
claims.iat = now;
113+
claims.nbf = now - 10;
114+
claims.exp = now + 60;
115+
} else if (state === 'expired') {
116+
claims.iat = now - 600;
117+
claims.nbf = now - 10 - 600;
118+
claims.exp = now + 60 - 600;
119+
} else if (state === 'early') {
120+
claims.iat = now + 600;
121+
claims.nbf = now - 10 + 600;
122+
claims.exp = now + 60 + 600;
123+
}
124+
return {
125+
token: jwt.sign(claims, rsa.private, {
126+
algorithm: 'RS256',
127+
header: { kid: ins_id },
128+
}),
129+
claims,
130+
};
131+
};
132+
const config = Object.freeze({
133+
pk,
134+
sk,
135+
generateToken,
136+
jwks,
137+
pkHost,
138+
});
139+
allConfigs.push(config);
140+
return config;
141+
}
142+
143+
export function getJwksFromSecretKey(sk: any) {
144+
return allConfigs.find((x: any) => x.sk === sk)?.jwks;
145+
}

integration/templates/next-app-router/package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
"start": "next start"
1010
},
1111
"dependencies": {
12+
"@clerk/backend": "file:.yalc/@clerk/backend",
13+
"@clerk/clerk-react": "file:.yalc/@clerk/clerk-react",
14+
"@clerk/nextjs": "file:.yalc/@clerk/nextjs",
15+
"@clerk/shared": "file:.yalc/@clerk/shared",
16+
"@clerk/types": "file:.yalc/@clerk/types",
1217
"@types/node": "^18.17.0",
1318
"@types/react": "18.2.14",
1419
"@types/react-dom": "18.2.6",

jest.config.handshake.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/** @type {import('ts-jest').JestConfigWithTsJest} */
2+
module.exports = {
3+
extensionsToTreatAsEsm: ['.ts'],
4+
testRegex: ['handshake.test.tsx?$'],
5+
moduleNameMapper: {
6+
'^(\\.{1,2}/.*)\\.js$': '$1',
7+
},
8+
transform: {
9+
// '^.+\\.[tj]sx?$' to process js/ts with `ts-jest`
10+
// '^.+\\.m?[tj]sx?$' to process js/ts/mjs/mts with `ts-jest`
11+
'^.+\\.tsx?$': [
12+
'ts-jest',
13+
{
14+
diagnostics: false,
15+
useESM: true,
16+
},
17+
],
18+
},
19+
};

packages/backend/src/tokens/interstitialRule.ts

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -171,17 +171,7 @@ export async function runInterstitialRules<T extends InterstitialRuleOptions>(
171171
}
172172

173173
async function verifyRequestState(options: InterstitialRuleOptions, token: string) {
174-
const { isSatellite, proxyUrl } = options;
175-
let issuer;
176-
if (isSatellite) {
177-
issuer = null;
178-
} else if (proxyUrl) {
179-
issuer = proxyUrl;
180-
} else {
181-
issuer = (iss: string) => iss.startsWith('https://clerk.') || iss.includes('.clerk.accounts');
182-
}
183-
184-
return verifyToken(token, { ...options, issuer });
174+
return verifyToken(token, { ...options });
185175
}
186176

187177
/**

packages/backend/src/tokens/jwt/verifyJwt.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import runtime from '../../runtime';
66
import { base64url } from '../../util/rfc4648';
77
import { TokenVerificationError, TokenVerificationErrorAction, TokenVerificationErrorReason } from '../errors';
88
import { getCryptoAlgorithm } from './algorithms';
9-
import type { IssuerResolver } from './assertions';
109
import {
1110
assertActivationClaim,
1211
assertAudienceClaim,
@@ -15,7 +14,6 @@ import {
1514
assertHeaderAlgorithm,
1615
assertHeaderType,
1716
assertIssuedAtClaim,
18-
assertIssuerClaim,
1917
assertSubClaim,
2018
} from './assertions';
2119
import { importKey } from './cryptoKeys';
@@ -82,13 +80,12 @@ export type VerifyJwtOptions = {
8280
audience?: string | string[];
8381
authorizedParties?: string[];
8482
clockSkewInMs?: number;
85-
issuer: IssuerResolver | string | null;
8683
key: JsonWebKey | string;
8784
};
8885

8986
export async function verifyJwt(
9087
token: string,
91-
{ audience, authorizedParties, clockSkewInMs, issuer, key }: VerifyJwtOptions,
88+
{ audience, authorizedParties, clockSkewInMs, key }: VerifyJwtOptions,
9289
): Promise<JwtPayload> {
9390
const clockSkew = clockSkewInMs || DEFAULT_CLOCK_SKEW_IN_SECONDS;
9491

@@ -108,7 +105,6 @@ export async function verifyJwt(
108105
assertSubClaim(sub);
109106
assertAudienceClaim([aud], [audience]);
110107
assertAuthorizedPartiesClaim(azp, authorizedParties);
111-
assertIssuerClaim(iss, issuer);
112108
assertExpirationClaim(exp, clockSkew);
113109
assertActivationClaim(nbf, clockSkew);
114110
assertIssuedAtClaim(iat, clockSkew);

packages/backend/src/tokens/keys.ts

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,6 @@ export type LoadClerkJWKFromRemoteOptions = {
9898
secretKey?: string;
9999
apiUrl?: string;
100100
apiVersion?: string;
101-
issuer?: string;
102101
};
103102

104103
/**
@@ -108,7 +107,6 @@ export type LoadClerkJWKFromRemoteOptions = {
108107
* The cache lasts 1 hour by default.
109108
*
110109
* @param {Object} options
111-
* @param {string} options.issuer - The issuer origin of the JWT
112110
* @param {string} options.kid - The id of the key that the JWT was signed with
113111
* @param {string} options.alg - The algorithm of the JWT
114112
* @param {number} options.jwksCacheTtlInMs - The TTL of the jwks cache (defaults to 1 hour)
@@ -118,27 +116,20 @@ export async function loadClerkJWKFromRemote({
118116
secretKey,
119117
apiUrl = API_URL,
120118
apiVersion = API_VERSION,
121-
issuer,
122119
kid,
123120
jwksCacheTtlInMs = JWKS_CACHE_TTL_MS,
124121
skipJwksCache,
125122
}: LoadClerkJWKFromRemoteOptions): Promise<JsonWebKey> {
126-
const shouldRefreshCache = !getFromCache(kid) && reachedMaxCacheUpdatedAt();
127-
if (skipJwksCache || shouldRefreshCache) {
128-
let fetcher;
129-
130-
if (secretKey) {
131-
fetcher = () => fetchJWKSFromBAPI(apiUrl, secretKey, apiVersion);
132-
} else if (issuer) {
133-
fetcher = () => fetchJWKSFromFAPI(issuer);
134-
} else {
123+
const needsFetch = !getFromCache(kid) || cacheHasExpired();
124+
if (skipJwksCache || needsFetch) {
125+
if (!secretKey) {
135126
throw new TokenVerificationError({
136127
action: TokenVerificationErrorAction.ContactSupport,
137128
message: 'Failed to load JWKS from Clerk Backend or Frontend API.',
138129
reason: TokenVerificationErrorReason.RemoteJWKFailedToLoad,
139130
});
140131
}
141-
132+
const fetcher = () => fetchJWKSFromBAPI(apiUrl, secretKey, apiVersion);
142133
const { keys } = await callWithRetry<{ keys: JsonWebKeyWithKid[] }>(fetcher);
143134

144135
if (!keys || !keys.length) {
@@ -231,6 +222,6 @@ async function fetchJWKSFromBAPI(apiUrl: string, key: string, apiVersion: string
231222
return response.json();
232223
}
233224

234-
function reachedMaxCacheUpdatedAt() {
225+
function cacheHasExpired() {
235226
return Date.now() - lastUpdatedAt >= MAX_CACHE_LAST_UPDATED_AT_SECONDS * 1000;
236227
}

packages/backend/src/tokens/request.ts

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,9 @@ export async function authenticateRequest(options: AuthenticateRequestOptions):
9595
const pkFapi = pk?.frontendApi || '';
9696
// determine proper FAPI url, taking into account multi-domain setups
9797
const frontendApi = proxyUrl || (!isDevOrStagingUrl(pkFapi) ? addClerkPrefix(domain) : '') || pkFapi;
98+
const frontendApiNoProtocol = frontendApi.replace(/http(s)?:\/\//, '');
9899

99-
const url = new URL(`https://${frontendApi}/v1/client/handshake`);
100+
const url = new URL(`https://${frontendApiNoProtocol}/v1/client/handshake`);
100101
url.searchParams.append('redirect_url', redirectUrl);
101102

102103
if (pk?.instanceType === 'development' && devBrowserToken) {
@@ -106,17 +107,7 @@ export async function authenticateRequest(options: AuthenticateRequestOptions):
106107
}
107108

108109
async function verifyRequestState(options: InterstitialRuleOptions, token: string) {
109-
const { isSatellite, proxyUrl } = options;
110-
let issuer;
111-
if (isSatellite) {
112-
issuer = null;
113-
} else if (proxyUrl) {
114-
issuer = proxyUrl;
115-
} else {
116-
issuer = (iss: string) => iss.startsWith('https://clerk.') || iss.includes('.clerk.accounts');
117-
}
118-
119-
return verifyToken(token, { ...options, issuer });
110+
return verifyToken(token, options);
120111
}
121112

122113
const clientUat = parseInt(ruleOptions.clientUat || '', 10) || 0;
@@ -196,6 +187,8 @@ export async function authenticateRequest(options: AuthenticateRequestOptions):
196187
buildRedirectToHandshake({
197188
publishableKey: ruleOptions.publishableKey!,
198189
devBrowserToken: ruleOptions.devBrowserToken!,
190+
proxyUrl: ruleOptions.proxyUrl,
191+
domain: ruleOptions.domain,
199192
redirectUrl: ruleOptions.request.url.toString(),
200193
}),
201194
);
@@ -211,6 +204,8 @@ export async function authenticateRequest(options: AuthenticateRequestOptions):
211204
buildRedirectToHandshake({
212205
publishableKey: ruleOptions.publishableKey!,
213206
devBrowserToken: ruleOptions.devBrowserToken!,
207+
proxyUrl: ruleOptions.proxyUrl,
208+
domain: ruleOptions.domain,
214209
redirectUrl: ruleOptions.request.url.toString(),
215210
}),
216211
);
@@ -228,6 +223,8 @@ export async function authenticateRequest(options: AuthenticateRequestOptions):
228223
buildRedirectToHandshake({
229224
publishableKey: ruleOptions.publishableKey!,
230225
devBrowserToken: ruleOptions.devBrowserToken!,
226+
proxyUrl: ruleOptions.proxyUrl,
227+
domain: ruleOptions.domain,
231228
redirectUrl: ruleOptions.request.url.toString(),
232229
}),
233230
);
@@ -257,6 +254,8 @@ export async function authenticateRequest(options: AuthenticateRequestOptions):
257254
buildRedirectToHandshake({
258255
publishableKey: ruleOptions.publishableKey!,
259256
devBrowserToken: ruleOptions.devBrowserToken!,
257+
proxyUrl: ruleOptions.proxyUrl,
258+
domain: ruleOptions.domain,
260259
redirectUrl: ruleOptions.request.url.toString(),
261260
}),
262261
);

packages/backend/src/tokens/verify.ts

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,9 @@ import { loadClerkJWKFromLocal, loadClerkJWKFromRemote } from './keys';
99
/**
1010
*
1111
*/
12-
export type VerifyTokenOptions = Pick<
13-
VerifyJwtOptions,
14-
'authorizedParties' | 'audience' | 'issuer' | 'clockSkewInMs'
15-
> & { jwtKey?: string; proxyUrl?: string } & Pick<
16-
LoadClerkJWKFromRemoteOptions,
17-
'secretKey' | 'apiUrl' | 'apiVersion' | 'jwksCacheTtlInMs' | 'skipJwksCache'
18-
>;
12+
export type VerifyTokenOptions = Pick<VerifyJwtOptions, 'authorizedParties' | 'audience' | 'clockSkewInMs'> & {
13+
jwtKey?: string;
14+
} & Pick<LoadClerkJWKFromRemoteOptions, 'secretKey' | 'apiUrl' | 'apiVersion' | 'jwksCacheTtlInMs' | 'skipJwksCache'>;
1915

2016
export async function verifyToken(token: string, options: VerifyTokenOptions): Promise<JwtPayload> {
2117
const {
@@ -25,7 +21,6 @@ export async function verifyToken(token: string, options: VerifyTokenOptions): P
2521
audience,
2622
authorizedParties,
2723
clockSkewInMs,
28-
issuer,
2924
jwksCacheTtlInMs,
3025
jwtKey,
3126
skipJwksCache,
@@ -38,9 +33,6 @@ export async function verifyToken(token: string, options: VerifyTokenOptions): P
3833

3934
if (jwtKey) {
4035
key = loadClerkJWKFromLocal(jwtKey);
41-
} else if (typeof issuer === 'string') {
42-
// Fetch JWKS from Frontend API if an issuer of type string has been provided
43-
key = await loadClerkJWKFromRemote({ issuer, kid, jwksCacheTtlInMs, skipJwksCache });
4436
} else if (secretKey) {
4537
// Fetch JWKS from Backend API using the key
4638
key = await loadClerkJWKFromRemote({ secretKey, apiUrl, apiVersion, kid, jwksCacheTtlInMs, skipJwksCache });
@@ -57,6 +49,5 @@ export async function verifyToken(token: string, options: VerifyTokenOptions): P
5749
authorizedParties,
5850
clockSkewInMs,
5951
key,
60-
issuer,
6152
});
6253
}

0 commit comments

Comments
 (0)