{"record":{"id":"60c2d8c5aae59221","repo":"tinyhumansai/openhuman","slug":"sign-in-callback-was-missing-a-token-please-try-a","errorCode":null,"errorMessage":"Sign-in callback was missing a token. Please try again.","messagePattern":"Sign-in callback was missing a token\\. Please try again\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/src/utils/desktopDeepLinkListener.ts","lineNumber":257,"sourceCode":"  window.dispatchEvent(new CustomEvent(SESSION_TOKEN_UPDATED_EVENT, { detail: { sessionToken } }));\n};\n\n/**\n * Handle an `openhuman://auth?token=...` deep link for login.\n *\n * `requireStateNonce` defaults to true for genuine OS-registered custom-scheme\n * deep links (the finding C3 vector — any external app can trigger\n * `openhuman://`). The same-origin web callback route (`WebCallbackPage`) passes\n * `false`: it is reached only through the app's own routing / the backend OAuth\n * redirect on the same origin, not via the OS scheme, so it is outside C3's scope.\n */\nconst handleAuthDeepLink = async (parsed: URL, requireStateNonce = true) => {\n  const token = parsed.searchParams.get('token');\n  const key = parsed.searchParams.get('key');\n  const state = parsed.searchParams.get('state');\n  if (!token) {\n    console.warn('[DeepLink] URL did not contain a token query parameter');\n    failDeepLinkAuthProcessing('Sign-in callback was missing a token. Please try again.');\n    return;\n  }\n\n  // CSRF / session-fixation guard (finding C3): only honour an auth deep link\n  // whose `state` matches a nonce this app generated before starting the flow.\n  // This is what stops a hostile page from triggering the OS custom scheme\n  // `openhuman://auth?token=<attacker_jwt>&key=auth` and silently logging the\n  // victim into the attacker's account. The `key=auth` raw-JWT path in\n  // particular is ONLY safe behind this check on the custom-scheme transport.\n  if (requireStateNonce && !verifyAndConsumeAuthDeepLinkState(state)) {\n    console.warn('[DeepLink][auth] rejecting auth deep link: missing or unrecognized state nonce');\n    failDeepLinkAuthProcessing('Sign-in could not be verified. Please start sign-in again.');\n    return;\n  }\n\n  beginDeepLinkAuthProcessing();\n\n  try {","sourceCodeStart":239,"sourceCodeEnd":275,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/app/src/utils/desktopDeepLinkListener.ts#L239-L275","documentation":"An openhuman://auth sign-in deep link arrived without a token query parameter, so there is nothing to exchange for a session — the flow fails fast with a user-facing message. This is the generic guard in handleAuthDeepLink (before the CSRF state check): the URL parsed successfully but carried no credential, typically a truncated/malformed redirect or a provider error redirect.","triggerScenarios":"Thrown at app/src/utils/desktopDeepLinkListener.ts:257 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Retry sign-in from the app — a fresh flow produces a well-formed callback URL","If it repeats, inspect the redirected URL (browser address bar) for where the token parameter was dropped","Check the backend OAuth redirect configuration for openhuman:// callback correctness","The state nonce guard would also reject stale links; starting over is always safe"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}