Skip to content

Commit 24a1d3c

Browse files
brkalowSokratisVidroscolinclerknikosdouvlis
authored andcommitted
feat(repo): Add E2E test suite for handshake and fix sdk-node exports (#2331)
* feat(backend): Try the new Client Handshake mechanism * feat(backend): Update authenticateRequest handler to support multi-domain handshake * feat(repo): Introduce tests for client handshake (#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]> * chore(backend): Refactor authenticateRequest to clarify logic * fix(backend): Fix options passing to authenticateRequest * feat(backend): Add sec-fetch-dest check for satellite sync, adjust tests to support additional URLs * feat(backend): Account for clock skew in dev, but still log error * feat(backend): Refactor backend tests to account for recent refactoring to authenticateRequest * feat(backend): Treat handshake payload as a signed jwt * fix(backend): Add tests and adjust logic to ensure existing tests pass * chore(backend): Refactor tests to conform to new method signature * chore(repo): Add changeset * feat(*): Drop interstitial (#2304) * feat(backend): Remove interstitial endpoints * feat(backend,types): Remove local interstitial script * feat(types): Clean retheme types * feat(backend): Remove interstitial and interstitial rules * feat(clerk-js): Remove interstitial from clerk-js * feat(nextjs): Remove interstitial from authMiddleware * feat(fastify): Remove interstitial * feat(gatsby-plugin-clerk): Remove interstitial * feat(remix): Remove interstitial * feat(clerk-sdk-node): Remove interstitial * fix(nextjs): Always respect redirect header if found As it's possible that we trigger a redirect from authenticateRequest that isn't a handshake status (dev multi-domain sync, for example) * chore(repo): Fix sdk tests * fix(clerk-js): Fix tests related to db-jwt * fix(clerk-js): Keep hasJustSynced check * chore(*): Fix linter * chore(backend): Remove unused AuthErrorReason properties, destructure from authenticateContext * chore(clerk-js): Remove unused @ts-expect-error directive * feat(repo): Migrate handshake tests to e2e test suite * fix(nextjs): Ensure we respect location header from authenticateRequest() regardless of auth status * Create bright-ways-provide.md * chore(clerk-sdk-node): Properly export createClerkClient * chore(clerk-sdk-node): Properly export createClerkClient * fix(nextjs): Fix undefined headers in tests --------- Co-authored-by: Sokratis Vidros <[email protected]> Co-authored-by: Colin Sidoti <[email protected]> Co-authored-by: Nikos Douvlis <[email protected]> Co-authored-by: Colin Sidoti <[email protected]>
1 parent 4ae4eb4 commit 24a1d3c

File tree

9 files changed

+1020
-30
lines changed

9 files changed

+1020
-30
lines changed

.changeset/bright-ways-provide.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
---
2+
---

integration/testUtils/handshake.ts

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
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+
const 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+
generateHandshakeToken(payload: string[]) {
137+
return jwt.sign({ handshake: payload }, rsa.private, {
138+
algorithm: 'RS256',
139+
header: { kid: ins_id },
140+
});
141+
},
142+
jwks,
143+
pkHost,
144+
});
145+
allConfigs.push(config);
146+
return config;
147+
}
148+
149+
export function getJwksFromSecretKey(sk: any) {
150+
return allConfigs.find((x: any) => x.sk === sk)?.jwks;
151+
}

0 commit comments

Comments
 (0)