TryGhost/Ghost · error · BadRequestError

Could not determine origin of request. Please ensure an…

Error message

Could not determine origin of request. Please ensure an Origin or Referrer header is present.

What it means

A BadRequestError from `assignUserToSession` when `origin` is falsy. Ghost derives the request origin from the `Origin` header first, then falls back to `Referer`; if neither is present it cannot bind a trusted origin to the session and refuses to proceed. This is the login/session-creation path, so a missing origin is treated as an untrustworthy request.

Solutions

  1. Send an `Origin` header matching the configured admin URL on the request.
  2. For automation/integrations, use the Admin API with a Staff token/key instead of the browser session flow.
  3. Disable the browser extension/config that strips `Origin`/`Referer` for the admin domain.
  4. Ensure any reverse proxy forwards the original `Origin`/`Referer` headers to Ghost.

Example fix

// before
curl -X POST https://example.com/ghost/api/admin/session/ -d '...'

// after
curl -X POST https://example.com/ghost/api/admin/session/ \
  -H 'Origin: https://example.com' \
  -H 'Content-Type: application/json' \
  -d '{...}'
Defensive patterns

Strategy: validation

Validate before calling

function ensureRequestOrigin(headers) {
  const origin = headers.origin || (headers.referer ? new URL(headers.referer).origin : null);
  if (!origin) throw new Error('Missing Origin/Referer header; cannot bind session origin');
  return origin;
}

Type guard

const hasOriginOrReferer = (h) => Boolean(h?.origin || h?.referer);

Try / catch

try {
  await api.session.create(credentials);
} catch (err) {
  if (err.type === 'BadRequestError' && /Origin or Referrer/i.test(err.message)) addOriginHeader();
  else throw err;
}

Prevention

When it happens

Trigger: A login or session-initiation request that carries neither an `Origin` nor a `Referer` header — e.g. a direct `fetch`/`curl` without those headers, a browser request that strips them, or a privacy/proxy setup that removes both.

Common situations: Calling the session/auth endpoints from a server-side script or `curl` with no `Origin`/`Referer`; a strict privacy browser or extension stripping these headers; a non-browser client (CLI/SDK) hitting the user-facing auth flow instead of the API-key flow; a redirect chain that drops the `Referer`.

Related errors


AI-assisted analysis of TryGhost/Ghost@47d8b0e2ad (2026-08-13). Data as JSON: /api/errors/09ec2068abfe065b. Report an issue: GitHub.

Appendix: source

Thrown at ghost/core/core/server/services/auth/session/session-service.js:173

    /**
     * isVerificationRequired
     * Determines if 2FA verification is required based on site settings
     * @returns {boolean}
     */
    function isVerificationRequired() {
        return getSettingsCache('require_email_mfa') === true;
    }

    async function assignUserToSession({
        session,
        user,
        origin,
        userAgent,
        ip,
        verificationToken
    }) {
        if (!origin) {
            throw new BadRequestError({
                message: 'Could not determine origin of request. Please ensure an Origin or Referrer header is present.'
            });
        }

        if (session.user_id && session.user_id !== user.id) {
            invalidateAuthCodeChallenge(session);
        }

        session.user_id = user.id;
        session.origin = origin;
        session.user_agent = userAgent;
        session.ip = ip;

        // If a verification token was provided with the login request, verify it
        if (verificationToken) {
            const secret = getSettingsCache('admin_session_secret');
            const isAuthCodeVerified = verifyAuthCode(session, verificationToken, secret);

View on GitHub (pinned to 47d8b0e2ad)