calcom/cal.diy · error · HttpError

You must be logged in to do this

Error message

You must be logged in to do this

What it means

Thrown as an HttpError (HTTP 401) by the Dub add handler when req.session.user is falsy. The Dub OAuth install flow requires an authenticated Cal.com user to attribute the integration to; an absent session means the user is not logged in (or the session cookie expired).

Source

Thrown at packages/app-store/dub/api/add.ts:14

import type { NextApiRequest, NextApiResponse } from "next";

import { HttpError } from "@calcom/lib/http-error";
import { defaultHandler } from "@calcom/lib/server/defaultHandler";
import { defaultResponder } from "@calcom/lib/server/defaultResponder";

import getParsedAppKeysFromSlug from "../../_utils/getParsedAppKeysFromSlug";
import { dubAppKeysSchema, scopeString } from "../lib/utils";

async function handler(req: NextApiRequest, res: NextApiResponse) {
  const loggedInUser = req.session?.user;

  if (!loggedInUser) {
    throw new HttpError({ statusCode: 401, message: "You must be logged in to do this" });
  }

  // Ideally this should never happen, as email is there in session user but typings aren't accurate it seems
  // TODO: So, confirm and later fix the typings
  if (!loggedInUser.email) {
    throw new HttpError({ statusCode: 400, message: "Session user must have an email" });
  }

  const { teamId } = req.query;
  const { client_id, redirect_uris } = await getParsedAppKeysFromSlug("dub", dubAppKeysSchema);

  const url = new URL("https://app.dub.co/oauth/authorize");
  url.searchParams.append("client_id", client_id);
  url.searchParams.append("redirect_uri", redirect_uris);
  url.searchParams.append("response_type", "code");
  url.searchParams.append("scope", scopeString);
  if (typeof teamId === "string" && !Number.isNaN(Number(teamId))) {
    url.searchParams.append("state", JSON.stringify({ teamId: Number(teamId) }));

View on GitHub (pinned to 176037d0af)

Solutions

  1. Ensure the user is logged into Cal.com before navigating to the Dub install URL.
  2. Verify NEXTAUTH_SECRET and NEXTAUTH_URL are set correctly so sessions persist.
  3. If using a reverse proxy, confirm cookie SameSite/Secure attributes pass through.
  4. Redirect unauthenticated users to the login page with a returnTo to /apps/dub/install instead of throwing.

Example fix

// before
if (!loggedInUser) {
  throw new HttpError({ statusCode: 401, message: "You must be logged in to do this" });
}

// after - send to login with callback
if (!loggedInUser) {
  res.redirect(`${WEBAPP_URL}/auth/login?callbackUrl=${encodeURIComponent(req.url ?? "/apps/dub/install")}`);
  return;
}
Defensive patterns

Strategy: validation

Validate before calling

const session = await getSession({ req });
if (!session?.user) {
  res.redirect(`${WEBAPP_URL}/auth/login?callbackUrl=${encodeURIComponent("/apps/dub/install")}`);
  return;
}

Type guard

const hasSessionUser = (req: NextApiRequest): boolean =>
  typeof req.session?.user?.id === "number";

Try / catch

try {
  await handler(req, res);
} catch (err) {
  if (err instanceof HttpError && err.statusCode === 401) {
    res.redirect(`${WEBAPP_URL}/auth/login?callbackUrl=${encodeURIComponent(req.url ?? "")}`);
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: Hitting POST/GET /api/dub/add without a valid NextAuth session cookie; session expired; route accessed by an unauthenticated browser or curl request.

Common situations: Session cookie expired between loading the integrations page and clicking 'Install Dub'; the user opened the install link in an incognito window; NextAuth session cookie blocked by third-party cookie restrictions.

Related errors


AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12). Data as JSON: /api/errors/2ac58b0bd7a29e9d. Report an issue: GitHub.