{"record":{"id":"495dd2ed77df0aff","repo":"RocketChat/Rocket.Chat","slug":"invalid-response-from-login-code-redemption","errorCode":null,"errorMessage":"Invalid response from login code redemption","messagePattern":"Invalid response from login code redemption","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/client/views/root/hooks/useOAuthLogin.ts","lineNumber":19,"sourceCode":"import { useEndpoint, useRouter, useSearchParameter, useLoginWithToken } from '@rocket.chat/ui-contexts';\nimport { useMutation } from '@tanstack/react-query';\nimport { useEffect } from 'react';\n\nimport { buildDeepLinkURL } from '../../../lib/buildAuthDeeplinkURL';\n\nexport const useOAuthLogin = () => {\n\tconst router = useRouter();\n\tconst loginCode = useSearchParameter('loginCode');\n\tconst loginClient = useSearchParameter('loginClient');\n\tconst redeemLoginCode = useEndpoint('POST', '/v1/loginCode.redeem');\n\tconst loginWithToken = useLoginWithToken();\n\n\tconst { mutate: redeemLoginCodeMutation } = useMutation({\n\t\tmutationFn: async (loginCode: string) => {\n\t\t\tconst { loginToken, userId } = await redeemLoginCode({ code: loginCode });\n\n\t\t\tif (!loginToken || !userId) {\n\t\t\t\tthrow new Error('Invalid response from login code redemption');\n\t\t\t}\n\n\t\t\treturn { loginToken, userId };\n\t\t},\n\t\tonSuccess: async ({ loginToken, userId }) => {\n\t\t\tif (loginClient === 'desktop' || loginClient === 'mobile') {\n\t\t\t\twindow.location.href = buildDeepLinkURL(loginToken, userId);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tawait loginWithToken(loginToken);\n\t\t\trouter.navigate('/home', { replace: true });\n\t\t},\n\t\tonError: (error) => {\n\t\t\tconsole.error('Failed to redeem login code for client redirect', error);\n\t\t\trouter.navigate('/login', { replace: true });\n\t\t},\n\t});","sourceCodeStart":1,"sourceCodeEnd":37,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/client/views/root/hooks/useOAuthLogin.ts#L1-L37","documentation":"Thrown by the useOAuthLogin mutation when POST /v1/loginCode.redeem returns a response missing loginToken or userId. The redemption call succeeded at the HTTP level but the payload is incomplete, so no token is available to complete the deep-link or loginWithToken flow.","triggerScenarios":"loginCode.redeem returns success with a missing/null loginToken or userId; the code was already consumed or expired and the server responded with an incomplete body; malformed OAuth callback integration returning an unexpected shape.","commonSituations":"Deep-link login (mobile/desktop) where the one-time code expired between issuance and redemption; OAuth provider misconfiguration; replay of an already-used login code.","solutions":["Regenerate the login code (restart the OAuth/login flow) so a fresh, unconsumed code is redeemed.","Verify the loginCode.redeem endpoint on the server returns both loginToken and userId for valid codes.","In onError, redirect the user back to the login page with a clear 'code expired' message."],"exampleFix":"// before\nconst { loginToken, userId } = await redeemLoginCode({ code: loginCode });\nif (!loginToken || !userId) {\n  throw new Error('Invalid response from login code redemption');\n}\n\n// after\nconst res = await redeemLoginCode({ code: loginCode });\nif (!res?.loginToken || !res?.userId) {\n  throw new Error(`Invalid response from login code redemption (token=${!!res?.loginToken}, userId=${!!res?.userId})`);\n}","handlingStrategy":"try-catch","validationCode":"// Sanity-check the code format before redeeming (e.g. length/charset) to fail fast.\nif (!loginCode || loginCode.length < 8) {\n  dispatchToastMessage({ type: 'error', message: 'Invalid or expired login code' });\n  router.navigate('/login', { replace: true });\n  return;\n}","typeGuard":"const hasRedeemResponse = (r: unknown): r is { loginToken: string; userId: string } =>\n  typeof r === 'object' && r !== null &&\n  typeof (r as any).loginToken === 'string' && (r as any).loginToken.length > 0 &&\n  typeof (r as any).userId === 'string' && (r as any).userId.length > 0;","tryCatchPattern":"useMutation({\n  mutationFn: async (code: string) => {\n    const res = await redeemLoginCode({ code });\n    if (!hasRedeemResponse(res)) {\n      throw new Error('Invalid response from login code redemption');\n    }\n    return res;\n  },\n  onError: () => {\n    router.navigate('/login', { replace: true });\n  },\n});","preventionTips":["Redeem login codes immediately after generation; they are short-lived and one-time.","Do not reuse or replay codes across clients.","On failure, restart the OAuth flow to obtain a fresh code."],"tags":["client","auth","oauth","login","deep-link"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}