diff --git a/src/client/ClientGameRunner.ts b/src/client/ClientGameRunner.ts index 2bacd56e2..55badacca 100644 --- a/src/client/ClientGameRunner.ts +++ b/src/client/ClientGameRunner.ts @@ -57,7 +57,6 @@ export interface LobbyConfig { playerName: string; clientID: ClientID; gameID: GameID; - token: string; turnstileToken: string | null; // GameStartInfo only exists when playing a singleplayer game. gameStartInfo?: GameStartInfo; diff --git a/src/client/Main.ts b/src/client/Main.ts index c4d0ecc32..d5a70c1ad 100644 --- a/src/client/Main.ts +++ b/src/client/Main.ts @@ -8,7 +8,7 @@ import { GameType } from "../core/game/Game"; import { UserSettings } from "../core/game/UserSettings"; import "./AccountModal"; import { getUserMe } from "./Api"; -import { getPlayToken, userAuth } from "./Auth"; +import { userAuth } from "./Auth"; import { joinLobby } from "./ClientGameRunner"; import { fetchCosmetics } from "./Cosmetics"; import "./DarkModeButton"; @@ -495,7 +495,6 @@ class Client { }, turnstileToken: await this.getTurnstileToken(lobby), playerName: this.usernameInput?.getCurrentUsername() ?? "", - token: await getPlayToken(), clientID: lobby.clientID, gameStartInfo: lobby.gameStartInfo ?? lobby.gameRecord?.info, gameRecord: lobby.gameRecord, diff --git a/src/client/Transport.ts b/src/client/Transport.ts index 9f4f1f5a7..8c94d215f 100644 --- a/src/client/Transport.ts +++ b/src/client/Transport.ts @@ -25,6 +25,7 @@ import { Winner, } from "../core/Schemas"; import { replacer } from "../core/Util"; +import { getPlayToken } from "./Auth"; import { LobbyConfig } from "./ClientGameRunner"; import { LocalServer } from "./LocalServer"; @@ -388,25 +389,25 @@ export class Transport { } } - joinGame() { + async joinGame() { this.sendMsg({ type: "join", gameID: this.lobbyConfig.gameID, clientID: this.lobbyConfig.clientID, - token: this.lobbyConfig.token, username: this.lobbyConfig.playerName, cosmetics: this.lobbyConfig.cosmetics, turnstileToken: this.lobbyConfig.turnstileToken, + token: await getPlayToken(), } satisfies ClientJoinMessage); } - rejoinGame(lastTurn: number) { + async rejoinGame(lastTurn: number) { this.sendMsg({ type: "rejoin", gameID: this.lobbyConfig.gameID, clientID: this.lobbyConfig.clientID, lastTurn: lastTurn, - token: this.lobbyConfig.token, + token: await getPlayToken(), } satisfies ClientRejoinMessage); } diff --git a/src/server/Worker.ts b/src/server/Worker.ts index 87b3e1d65..1bbacc1e8 100644 --- a/src/server/Worker.ts +++ b/src/server/Worker.ts @@ -337,8 +337,10 @@ export async function startWorker() { // Verify token signature const result = await verifyClientToken(clientMsg.token, config); - if (result === false) { - log.warn("Unauthorized: Invalid token"); + if (result.type === "error") { + log.warn(`Invalid token: ${result.message}`, { + clientID: clientMsg.clientID, + }); ws.close(1002, "Unauthorized"); return; } diff --git a/src/server/jwt.ts b/src/server/jwt.ts index b0a81dc8b..29453eb9a 100644 --- a/src/server/jwt.ts +++ b/src/server/jwt.ts @@ -11,17 +11,18 @@ import { PersistentIdSchema } from "../core/Schemas"; type TokenVerificationResult = | { + type: "success"; persistentId: string; claims: TokenPayload | null; } - | false; + | { type: "error"; message: string }; export async function verifyClientToken( token: string, config: ServerConfig, ): Promise { if (PersistentIdSchema.safeParse(token).success) { - return { persistentId: token, claims: null }; + return { type: "success", persistentId: token, claims: null }; } try { const issuer = config.jwtIssuer(); @@ -34,15 +35,23 @@ export async function verifyClientToken( }); const result = TokenPayloadSchema.safeParse(payload); if (!result.success) { - const error = z.prettifyError(result.error); - console.warn("Error parsing token payload", error); - return false; + return { + type: "error", + message: z.prettifyError(result.error), + }; } const claims = result.data; const persistentId = claims.sub; - return { persistentId, claims }; + return { type: "success", persistentId, claims }; } catch (e) { - return false; + const message = + e instanceof Error + ? e.message + : typeof e === "string" + ? e + : "An unknown error occurred"; + + return { type: "error", message }; } }