diff --git a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-segments-should-look-right-3-Google-Chrome-linux.png b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-segments-should-look-right-3-Google-Chrome-linux.png index 06a2716a3..26956ddbc 100644 Binary files a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-segments-should-look-right-3-Google-Chrome-linux.png and b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-segments-should-look-right-3-Google-Chrome-linux.png differ diff --git a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-segments-should-look-right-4-Google-Chrome-linux.png b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-segments-should-look-right-4-Google-Chrome-linux.png index 6aa1e34f3..5f741433b 100644 Binary files a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-segments-should-look-right-4-Google-Chrome-linux.png and b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-segments-should-look-right-4-Google-Chrome-linux.png differ diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 801b9af36..aaf7e8a6c 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -222,3 +222,6 @@ export const CODE_QUERY_PARAM = 'code' /** A query parameter to skip the sign-on view if unnecessary. */ export const IMMEDIATE_SIGN_IN_IF_NECESSARY_QUERY_PARAM = 'immediate-sign-in-if-necessary' + +// Only used by the desktop app +export const OAUTH2_DEVICE_CLIENT_ID = '2af127fb-e14e-400a-9c57-a9ed08d1a5b7' diff --git a/src/machines/authMachine.ts b/src/machines/authMachine.ts index 472f18ac0..45b2d328b 100644 --- a/src/machines/authMachine.ts +++ b/src/machines/authMachine.ts @@ -7,7 +7,7 @@ import { } from '@src/env' import { assign, fromPromise, setup } from 'xstate' -import { COOKIE_NAME } from '@src/lib/constants' +import { COOKIE_NAME, OAUTH2_DEVICE_CLIENT_ID } from '@src/lib/constants' import { getUser as getUserDesktop, readTokenFile, @@ -254,8 +254,32 @@ async function getAndSyncStoredToken(input: { async function logout() { localStorage.removeItem(TOKEN_PERSIST_KEY) if (isDesktop()) { - await writeTokenFile('') - return Promise.resolve(null) + try { + let token = await readTokenFile() + + if (token) { + try { + await fetch(withBaseUrl('/oauth2/token/revoke'), { + method: 'POST', + credentials: 'include', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: new URLSearchParams({ + token: token, + client_id: OAUTH2_DEVICE_CLIENT_ID, + }).toString(), + }) + } catch (e) { + console.error('Error revoking token:', e) + } + + await writeTokenFile('') + return Promise.resolve(null) + } + } catch (e) { + console.error('Error reading token during logout (ignoring):', e) + } } return fetch(withBaseUrl('/logout'), { diff --git a/src/main.ts b/src/main.ts index f7c30ad35..27bf5b8f9 100644 --- a/src/main.ts +++ b/src/main.ts @@ -28,7 +28,10 @@ import { parseCLIArgs, } from '@src/commandLineArgs' import { initPromiseNode } from '@src/lang/wasmUtilsNode' -import { ZOO_STUDIO_PROTOCOL } from '@src/lib/constants' +import { + ZOO_STUDIO_PROTOCOL, + OAUTH2_DEVICE_CLIENT_ID, +} from '@src/lib/constants' import getCurrentProjectFile from '@src/lib/getCurrentProjectFile' import { reportRejection } from '@src/lib/trap' import { @@ -402,7 +405,7 @@ ipcMain.handle('startDeviceFlow', async (_, host: string) => { // We can hardcode the client ID. // This value is safe to be embedded in version control. // This is the client ID of the KittyCAD app. - client_id: '2af127fb-e14e-400a-9c57-a9ed08d1a5b7', + client_id: OAUTH2_DEVICE_CLIENT_ID, token_endpoint_auth_method: 'none', })