RocketChat/Rocket.Chat · error · Error

Invalid response from login code redemption

Error message

Invalid response from login code redemption

What it means

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.

Source

Thrown at apps/meteor/client/views/root/hooks/useOAuthLogin.ts:19

import { useEndpoint, useRouter, useSearchParameter, useLoginWithToken } from '@rocket.chat/ui-contexts';
import { useMutation } from '@tanstack/react-query';
import { useEffect } from 'react';

import { buildDeepLinkURL } from '../../../lib/buildAuthDeeplinkURL';

export const useOAuthLogin = () => {
	const router = useRouter();
	const loginCode = useSearchParameter('loginCode');
	const loginClient = useSearchParameter('loginClient');
	const redeemLoginCode = useEndpoint('POST', '/v1/loginCode.redeem');
	const loginWithToken = useLoginWithToken();

	const { mutate: redeemLoginCodeMutation } = useMutation({
		mutationFn: async (loginCode: string) => {
			const { loginToken, userId } = await redeemLoginCode({ code: loginCode });

			if (!loginToken || !userId) {
				throw new Error('Invalid response from login code redemption');
			}

			return { loginToken, userId };
		},
		onSuccess: async ({ loginToken, userId }) => {
			if (loginClient === 'desktop' || loginClient === 'mobile') {
				window.location.href = buildDeepLinkURL(loginToken, userId);
				return;
			}

			await loginWithToken(loginToken);
			router.navigate('/home', { replace: true });
		},
		onError: (error) => {
			console.error('Failed to redeem login code for client redirect', error);
			router.navigate('/login', { replace: true });
		},
	});

View on GitHub (pinned to f9d3ec372b)

Solutions

  1. Regenerate the login code (restart the OAuth/login flow) so a fresh, unconsumed code is redeemed.
  2. Verify the loginCode.redeem endpoint on the server returns both loginToken and userId for valid codes.
  3. In onError, redirect the user back to the login page with a clear 'code expired' message.

Example fix

// before
const { loginToken, userId } = await redeemLoginCode({ code: loginCode });
if (!loginToken || !userId) {
  throw new Error('Invalid response from login code redemption');
}

// after
const res = await redeemLoginCode({ code: loginCode });
if (!res?.loginToken || !res?.userId) {
  throw new Error(`Invalid response from login code redemption (token=${!!res?.loginToken}, userId=${!!res?.userId})`);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Sanity-check the code format before redeeming (e.g. length/charset) to fail fast.
if (!loginCode || loginCode.length < 8) {
  dispatchToastMessage({ type: 'error', message: 'Invalid or expired login code' });
  router.navigate('/login', { replace: true });
  return;
}

Type guard

const hasRedeemResponse = (r: unknown): r is { loginToken: string; userId: string } =>
  typeof r === 'object' && r !== null &&
  typeof (r as any).loginToken === 'string' && (r as any).loginToken.length > 0 &&
  typeof (r as any).userId === 'string' && (r as any).userId.length > 0;

Try / catch

useMutation({
  mutationFn: async (code: string) => {
    const res = await redeemLoginCode({ code });
    if (!hasRedeemResponse(res)) {
      throw new Error('Invalid response from login code redemption');
    }
    return res;
  },
  onError: () => {
    router.navigate('/login', { replace: true });
  },
});

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12). Data as JSON: /api/errors/495dd2ed77df0aff. Report an issue: GitHub.