Skip to content

fix: validate GitHub API responses in SSO authentication#6137

Open
lawrence3699 wants to merge 1 commit intoFlowiseAI:mainfrom
lawrence3699:fix/github-sso-email-fetch-error-handling
Open

fix: validate GitHub API responses in SSO authentication#6137
lawrence3699 wants to merge 1 commit intoFlowiseAI:mainfrom
lawrence3699:fix/github-sso-email-fetch-error-handling

Conversation

@lawrence3699
Copy link
Copy Markdown

@lawrence3699 lawrence3699 commented Apr 3, 2026

Ran into this while setting up GitHub SSO on a self-hosted Flowise instance. When the GitHub token was misconfigured, the login flow crashed with TypeError: emails.find is not a function instead of showing a meaningful error.

The root cause: GithubSSO.ts calls fetch() against GitHub APIs in three places but never checks response.ok before calling .json(). When GitHub returns a non-2xx status (401, 403, 500), the response body is an error object like {"message":"Bad credentials"}, not an array — so emails.find() blows up. If GitHub returns a 5xx HTML error page, .json() itself throws a SyntaxError.

This affects:

  1. Email fetch during login (passport callback) — a revoked or expired token crashes the whole callback with TypeError, and since there's no try-catch wrapper, the error propagates unhandled
  2. testSetup — admin testing SSO configuration gets a cryptic error instead of a clear "GitHub returned 500"
  3. refreshToken — expired refresh tokens crash instead of returning a clean error

The fix adds response.ok checks before .json() in all three fetch calls, following the same pattern already used in packages/components/src/utils.ts (line 1490):

if (!refreshResponse.ok) {
    const errorData = await refreshResponse.text()
    throw new Error(\`Failed to refresh token: \${refreshResponse.status} \${refreshResponse.statusText} - \${errorData}\`)
}

For the email fetch callback, I also wrapped the whole body in try-catch and added an Array.isArray guard so that an unexpected response shape gets surfaced as SSO_LOGIN_FAILED with a clear message rather than a raw TypeError.

Reproduction:

// What happens without response.ok check when GitHub returns 401:
const githubErrorBody = { message: "Bad credentials", documentation_url: "..." }
githubErrorBody.find(e => e.primary)  // TypeError: githubErrorBody.find is not a function

Tests: Added GithubSSO.test.ts with 5 tests demonstrating the crash scenarios (TypeError on non-array response, SyntaxError on HTML error page) and verifying the fix produces clear error messages.

Copilot AI review requested due to automatic review settings April 3, 2026 07:42
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Improves robustness of the GitHub SSO OAuth callback by handling non-OK responses and unexpected payloads from the GitHub /user/emails API, preventing callback crashes and enabling user-facing error redirects.

Changes:

  • Wrap GitHub email-fetch logic in try/catch and return SSO_LOGIN_FAILED on failure.
  • Check emailResponse.ok before parsing JSON and validate the parsed payload is an array.
  • Keep existing primary-email selection logic while avoiding .find() on non-arrays.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

let primaryEmail = emails.find((email: any) => email.primary && email.verified)?.email
if (!primaryEmail && emails.length > 0) {
primaryEmail = emails[0].email
}
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

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

primaryEmail can still end up undefined (e.g., if the /user/emails array is empty or entries are missing email). This then gets passed into verifyAndLogin even though it expects a string, leading to a DB lookup with an invalid email and a generic failure. Consider explicitly validating primaryEmail is a non-empty string and returning SSO_LOGIN_FAILED (with a clear message) when no usable email is available.

Suggested change
}
}
if (typeof primaryEmail !== 'string' || primaryEmail.trim() === '') {
return done(
{ name: 'SSO_LOGIN_FAILED', message: 'No usable email address returned by GitHub' },
undefined
)
}

Copilot uses AI. Check for mistakes.
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 enhances the GitHub SSO implementation by adding comprehensive error handling, response validation, and try-catch blocks to the email fetching logic. Feedback suggests updating the deprecated "token" prefix in the Authorization header to "Bearer" to align with current API standards and adding a validation check to ensure an email address is found before proceeding with the login flow to prevent potential downstream errors.

// Fetch emails from GitHub API using the access token.
const emailResponse = await fetch('https://api.github.com/user/emails', {
headers: {
Authorization: `token ${accessToken}`,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

GitHub has deprecated the token prefix for the Authorization header. It is recommended to use Bearer instead to align with current GitHub API standards and ensure long-term compatibility.

Suggested change
Authorization: `token ${accessToken}`,
Authorization: 'Bearer ' + accessToken,

Comment on lines +59 to +63
let primaryEmail = emails.find((email: any) => email.primary && email.verified)?.email
if (!primaryEmail && emails.length > 0) {
primaryEmail = emails[0].email
}
return this.verifyAndLogin(this.app, primaryEmail, done, profile, accessToken, refreshToken)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

If no email is found in the GitHub response (e.g., an empty array or no primary/verified email), primaryEmail will be undefined. Passing undefined to verifyAndLogin can cause database errors or unexpected behavior during the registration/login flow. It is better to validate the presence of an email address and return a specific error message if none is found.

                            let primaryEmail = emails.find((email: any) => email.primary && email.verified)?.email
                            if (!primaryEmail && emails.length > 0) {
                                primaryEmail = emails[0].email
                            }

                            if (!primaryEmail) {
                                return done(
                                    { name: 'SSO_LOGIN_FAILED', message: 'No email address found in your GitHub account.' },
                                    undefined
                                )
                            }

                            return this.verifyAndLogin(this.app, primaryEmail, done, profile, accessToken, refreshToken)
References
  1. Multiple early returns for validation can be preferable to a single error-aggregating block if the latter is considered more confusing or less readable.

Check response.ok before calling .json() on all three GitHub API fetch
calls in GithubSSO, preventing crashes when GitHub returns error statuses.
@lawrence3699 lawrence3699 force-pushed the fix/github-sso-email-fetch-error-handling branch from c54704a to b1ca671 Compare April 3, 2026 07:50
@lawrence3699 lawrence3699 changed the title fix: handle GitHub API errors in SSO email fetch callback fix: validate GitHub API responses in SSO authentication Apr 3, 2026
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.

2 participants