Skip to content

bug: rm refresh endpoint and require auth#6262

Draft
chloebyun-wd wants to merge 4 commits intomainfrom
bug/524/unauthenticated-oauth-refresh-token-fix
Draft

bug: rm refresh endpoint and require auth#6262
chloebyun-wd wants to merge 4 commits intomainfrom
bug/524/unauthenticated-oauth-refresh-token-fix

Conversation

@chloebyun-wd
Copy link
Copy Markdown

Original attack chain vs. current fix

Step Attack Before fix After fix
1 Attacker calls POST /refresh/:id with no auth Whitelisted → middleware calls next() → handler runs Still whitelisted → middleware calls next() → handler checks x-flowise-internal-key header
2 Handler processes request Decrypts credential, calls OAuth provider, returns access_token providedKey is undefined → returns 401 immediately
3 Token in response tokenInfo: { ...tokenData } leaks access_token Response only contain has_new_refresh_token and expires_at

The Docker validation test (POST /refresh/fake-uuid returning {"message":"Credential not found"} instead of 401) would now return {"success":false,"message":"Unauthorized"} — a 401 before the credential lookup even happens.

All five reported impacts mitigated

Impact Mitigated by
OAuth2 access token theft Handler rejects requests without valid x-flowise-internal-key → attacker gets 401 before any credential is touched
Third-party account access Same — no token is ever returned to an unauthenticated caller
Client secret transmission Same — the OAuth provider refresh call never executes
Token leakage in response Even for legitimate callers, access_token/refresh_token are stripped from the response body
DoS via refresh token quota Auth check prevents unauthorized refresh attempts

Defense in depth layers

  1. Handler-level auth with crypto.timingSafeEqual — primary gate; prevents timing side-channel attacks on key comparison
  2. Token stripping from response — fallback; limits damage if auth is ever bypassed
  3. Key resolved via getEncryptionKey() — supports env var, AWS Secrets Manager, and key file (no single-point-of-failure)
  4. Key cached in memory — avoids file I/O or AWS API calls on every refresh request
  5. Key threaded via options.internalRefreshKey — server resolves the key once and passes it through the flow execution pipeline, so components don't depend on process.env directly

Architectural trade-off

The endpoint remains in WHITELIST_URLS so the global auth middleware doesn't block internal server-to-server calls (which carry no JWT/API key). This is acceptable because the handler's own auth check runs first, using the server's encryption key — which an external attacker cannot know.

Chloe Byun and others added 3 commits April 20, 2026 14:03
…ey, use timing-safe comparison

- Pass internalRefreshKey through executeAgentFlow, executeNode, and
  recursive sub-flow calls so OAuth2 refresh works in Agentflows
- Cache getEncryptionKey() result to avoid file I/O or AWS calls per request
- Use crypto.timingSafeEqual for key comparison to prevent timing attacks

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements an internal authentication mechanism for OAuth2 token refresh requests by introducing an 'x-flowise-internal-key' header and propagating it through the execution flow. It also enhances security by omitting sensitive token data from the refresh response. Feedback suggests addressing a potential runtime error in the timing-safe comparison logic and removing the local encryption key cache to prevent consistency issues during key rotation.

Comment thread packages/server/src/routes/oauth2/index.ts Outdated
Comment thread packages/server/src/routes/oauth2/index.ts Outdated
…ray wrap

- Use getEncryptionKey() directly instead of caching (avoids staleness on key rotation)
- Compare Buffer.length instead of string.length (handles multi-byte characters)
- Remove unnecessary new Uint8Array(Buffer.from(...)) double-wrapping

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@chloebyun-wd chloebyun-wd force-pushed the bug/524/unauthenticated-oauth-refresh-token-fix branch from 5256359 to 7d1a3f1 Compare April 21, 2026 23:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant