Skip to content

Commit d465d70

Browse files
authored
fix(backend): Fix getToken returning null when resolving the handshake payload (clerk#3764)
This PR fixes an issue on Remix where getToken() returns no token when redirecting back when sign-in and handshake are triggered. The issue exists because the getToken() is getting the session token from the request cookie, but when returning from an external sign-in page (e.g. OAuth or Account Portal) on the request there is still the __clerk_handshake cookie, because it's not yet resolved. The issue exists only on production, and also does not happen to nextjs, because middleware has already resolved the handshake. With this PR we pass the session token that exists inside the handshake payload to be returned when calling getToken().
1 parent c442839 commit d465d70

8 files changed

Lines changed: 40 additions & 7 deletions

File tree

.changeset/dry-yaks-buy.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@clerk/backend": patch
3+
---
4+
5+
Fix `getToken` returning `null` when signing in.

packages/astro/src/server/get-auth.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export const createGetAuth = ({ noAuthStatusMessage }: { noAuthStatusMessage: st
3636

3737
const jwt = decodeJwt(authToken as string);
3838
// @ts-expect-error - TODO: Align types
39-
return signedInAuthObject({ ...options, sessionToken: jwt.raw.text }, jwt.payload);
39+
return signedInAuthObject(options, jwt.raw.text, jwt.payload);
4040
};
4141
};
4242

packages/backend/src/tokens/__tests__/authObjects.test.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
import type { JwtPayload } from '@clerk/types';
12
import type QUnit from 'qunit';
23

3-
import { makeAuthObjectSerializable, signedOutAuthObject } from '../authObjects';
4+
import type { AuthenticateContext } from '../authenticateContext';
5+
import { makeAuthObjectSerializable, signedInAuthObject, signedOutAuthObject } from '../authObjects';
46

57
export default (QUnit: QUnit) => {
68
const { module, test } = QUnit;
@@ -15,4 +17,22 @@ export default (QUnit: QUnit) => {
1517
}
1618
});
1719
});
20+
21+
module('signedInAuthObject', () => {
22+
test('getToken returns the token passed in', async assert => {
23+
const mockAuthenticateContext = { sessionToken: 'authContextToken' } as AuthenticateContext;
24+
const authObject = signedInAuthObject(mockAuthenticateContext, 'token', {
25+
act: 'actor',
26+
sid: 'sessionId',
27+
org_id: 'orgId',
28+
org_role: 'orgRole',
29+
org_slug: 'orgSlug',
30+
org_permissions: 'orgPermissions',
31+
sub: 'userId',
32+
} as unknown as JwtPayload);
33+
34+
const token = await authObject.getToken();
35+
assert.strictEqual(token, 'token');
36+
});
37+
});
1838
};

packages/backend/src/tokens/__tests__/authStatus.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ export default (QUnit: QUnit) => {
1212
assert.strictEqual(authObject.headers.get('x-clerk-auth-reason'), null);
1313
assert.strictEqual(authObject.headers.get('x-clerk-auth-message'), null);
1414
});
15+
16+
test('authObject returned by toAuth() returns the token passed', async assert => {
17+
const signedInAuthObject = signedIn({} as any, { sid: 'sid' } as any, undefined, 'token').toAuth();
18+
const token = await signedInAuthObject.getToken();
19+
assert.strictEqual(token, 'token');
20+
});
1521
});
1622

1723
module('signed-out', () => {

packages/backend/src/tokens/authObjects.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ const createDebug = (data: AuthObjectDebugData | undefined) => {
7575
*/
7676
export function signedInAuthObject(
7777
authenticateContext: AuthenticateContext,
78+
sessionToken: string,
7879
sessionClaims: JwtPayload,
7980
): SignedInAuthObject {
8081
const {
@@ -89,7 +90,7 @@ export function signedInAuthObject(
8990
const apiClient = createBackendApiClient(authenticateContext);
9091
const getToken = createGetToken({
9192
sessionId,
92-
sessionToken: authenticateContext.sessionToken || '',
93+
sessionToken,
9394
fetcher: async (...args) => (await apiClient.sessions.getToken(...args)).jwt,
9495
});
9596

@@ -104,7 +105,7 @@ export function signedInAuthObject(
104105
orgPermissions,
105106
getToken,
106107
has: createHasAuthorization({ orgId, orgRole, orgPermissions, userId }),
107-
debug: createDebug({ ...authenticateContext }),
108+
debug: createDebug({ ...authenticateContext, sessionToken }),
108109
};
109110
}
110111

packages/backend/src/tokens/authStatus.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ export function signedIn(
8181
headers: Headers = new Headers(),
8282
token: string,
8383
): SignedInState {
84-
const authObject = signedInAuthObject(authenticateContext, sessionClaims);
84+
const authObject = signedInAuthObject(authenticateContext, token, sessionClaims);
8585
return {
8686
status: AuthStatus.SignedIn,
8787
reason: null,

packages/nextjs/src/server/buildClerkProps.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export const buildClerkProps: BuildClerkProps = (req, initState = {}) => {
5858
const jwt = decodeJwt(authToken as string);
5959

6060
// @ts-expect-error - TODO @nikos: Align types
61-
authObject = signedInAuthObject({ ...options, sessionToken: jwt.raw.text }, jwt.payload);
61+
authObject = signedInAuthObject(options, jwt.raw.text, jwt.payload);
6262
}
6363

6464
const sanitizedAuthObject = makeAuthObjectSerializable(stripPrivateDataFromObject({ ...authObject, ...initState }));

packages/nextjs/src/server/createGetAuth.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,9 @@ export const createGetAuth = ({
5555
const jwt = decodeJwt(authToken as string);
5656

5757
logger.debug('JWT debug', jwt.raw.text);
58+
5859
// @ts-expect-error - TODO @nikos: Align types
59-
return signedInAuthObject({ ...options, sessionToken: jwt.raw.text }, jwt.payload);
60+
return signedInAuthObject(options, jwt.raw.text, jwt.payload);
6061
}
6162

6263
return signedOutAuthObject(options);

0 commit comments

Comments
 (0)