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
- Send the user back through /api/v1/auth/login to obtain a fresh pair of token + refreshToken cookies.
- 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).
- 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.
- Confirm APP_URL origin matches the API origin, or adjust cookie sameSite/domain to fit your deployment.
- In tests, attach Cookie: refreshToken=<jwt> to the refresh request.
- 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
- Always send credentials: 'include' (browser) or use a cookie jar (node) on every request so the refreshToken cookie round-trips.
- Verify SECURE_COOKIES / NODE_ENV / APP_URL so the refresh cookie is actually being set in your environment (use SECURE_COOKIES=false over plain HTTP in dev).
- Don't call /refreshToken before a successful login has stored the cookie.
- Distinguish this 401 (no body, missing cookie) from the JWT-expired 401 (JSON body with REFRESH_TOKEN_EXPIRED) — only the latter is worth retrying.
- In tests, attach Cookie: refreshToken=<jwt> from the login response's Set-Cookie.
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
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Error: credentialsController.deleteCredentials - workspace $
- Error: credentialsController.getAllCredentials - workspace $
- Error: credentialsController.getCredentialById - workspace $
- Error: credentialsController.revealCredentialById - workspac
- Error: credentialsController.updateCredential - workspace ${
AI-assisted analysis of FlowiseAI/Flowise@abe4a8601a (2026-08-12).
Data as JSON: /api/errors/62e4ba17f1b3cdc0.
Report an issue: GitHub.