FlowiseAI/Flowise · error

Unauthorized

Error message

Unauthorized

What it means

Returned as HTTP 401 Unauthorized (via res.sendStatus(401)) by the POST /api/v1/auth/refreshToken handler when the refreshToken cookie is absent. This is the very first guard in the refresh flow — it fires before jwt.verify, so it tells you the client never sent a refresh token at all, not that the token was invalid/expired. Unlike the other errors, this one returns a bare 401 status with no JSON body.

Source

Thrown at packages/server/src/enterprise/middleware/passport/index.ts:237

                    return res.status(HttpStatusCode.Ok).json({ redirectUrl: '/organization-setup' })
                default:
                    return res.status(HttpStatusCode.Ok).json({ redirectUrl: '/organization-setup' })
            }
        }
        switch (platform) {
            case Platform.ENTERPRISE:
                if (!identityManager.isLicenseValid()) {
                    return res.status(HttpStatusCode.Ok).json({ redirectUrl: '/license-expired' })
                }
                return res.status(HttpStatusCode.Ok).json({ redirectUrl: '/signin' })
            default:
                return res.status(HttpStatusCode.Ok).json({ redirectUrl: '/signin' })
        }
    })

    app.post('/api/v1/auth/refreshToken', async (req, res) => {
        const refreshToken = req.cookies.refreshToken
        if (!refreshToken) return res.sendStatus(401)

        jwt.verify(refreshToken, getJWTRefreshTokenSecret(), async (err: any, payload: any) => {
            if (err || !payload) return res.status(401).json({ message: ErrorMessage.REFRESH_TOKEN_EXPIRED })
            // @ts-ignore
            const loggedInUser = req.user as LoggedInUser
            let isSSO = false
            let newTokenResponse: any = {}
            if (loggedInUser && loggedInUser.ssoRefreshToken) {
                try {
                    newTokenResponse = await identityManager.getRefreshToken(loggedInUser.ssoProvider, loggedInUser.ssoRefreshToken)
                    if (newTokenResponse.error) {
                        return res.status(401).json({ message: ErrorMessage.REFRESH_TOKEN_EXPIRED })
                    }
                    isSSO = true
                } catch (error) {
                    return res.status(401).json({ message: ErrorMessage.REFRESH_TOKEN_EXPIRED })
                }
            }

View on GitHub (pinned to abe4a8601a)

Solutions

  1. Send the user back through /api/v1/auth/login to obtain a fresh pair of token + refreshToken cookies.
  2. If you operate a non-browser client, capture Set-Cookie from the login response and replay the refreshToken cookie on refresh requests (use a cookie jar).
  3. Verify SECURE_COOKIES / NODE_ENV / APP_URL so the cookie is actually being set in your environment — over HTTP in dev, set SECURE_COOKIES=false.
  4. Confirm APP_URL origin matches the API origin, or adjust cookie sameSite/domain to fit your deployment.
  5. In tests, attach Cookie: refreshToken=<jwt> to the refresh request.
  6. On the client, only call /refreshToken after a prior successful login that returned Set-Cookie.

Example fix

// before — non-browser client with no cookie jar
await axios.post('/api/v1/auth/refreshToken') // 401: no cookie sent

// after — persist and replay the cookie
const jar = new CookieJar()
const client = axios.create({ jar, withCredentials: true })
await client.post('/api/v1/auth/login', { email, password }) // stores refreshToken
await client.post('/api/v1/auth/refreshToken')                // replays it
Defensive patterns

Strategy: validation

Validate before calling

// before calling /refreshToken, confirm the cookie exists (browser) or the jar has it (node)
async function refreshIfPossible(): Promise<void> {
  // browser
  if (typeof document !== 'undefined') {
    const hasRefresh = document.cookie.split('; ').some(c => c.startsWith('refreshToken='))
    if (!hasRefresh) {
      await auth.login(credentials) // no point refreshing without a cookie
      return
    }
  }
  await fetch('/api/v1/auth/refreshToken', { method: 'POST', credentials: 'include' })
}

Type guard

// For a node client with a cookie jar — narrow to a cookie that has the refresh token
function cookieJarHasRefresh(jar: { getCookiesSync: (url: string) => Array<{ key: string }> }, url: string): boolean {
  return jar.getCookiesSync(url).some(c => c.key === 'refreshToken')
}

Try / catch

// On 401 from a resource request, try refresh exactly once; if refresh itself 401s, send to login.
try {
  return await api.callProtected()
} catch (e) {
  if (e.response?.status !== 401) throw e
  try {
    await api.refreshToken() // may throw 401 with no body — that's this error
    return await api.callProtected()
  } catch (refreshErr) {
    if (refreshErr.response?.status === 401) {
      await auth.redirectToLogin() // refresh cookie was missing — refresh cannot succeed
      return
    }
    throw refreshErr
  }
}

Prevention

When it happens

Trigger: POST /api/v1/auth/refreshToken called with no refreshToken cookie. Browser cleared cookies (logout, devtools clear, privacy mode). SameSite=lax cookie dropped because the request is cross-site. Cookie expired or never set because login didn't reach setTokenOrCookies. Client is a non-browser API client that never stored the refresh-token cookie.

Common situations: User opened the app in a new incognito window. Third-party cookie blocking stripped the refresh cookie. APP_URL changed so the cookie domain/path no longer matches. SECURE_COOKIES=true in dev over HTTP, so the browser refused to set the cookie. SPA on a different origin than the API. Token expiry handling in the client called refresh before login completed.

Understand the failure class

Related errors


AI-assisted analysis of FlowiseAI/Flowise@abe4a8601a (2026-08-12). Data as JSON: /api/errors/62e4ba17f1b3cdc0. Report an issue: GitHub.