chore(oauth): remove unused github-repo generic OAuth provider (#3543)

This commit is contained in:
Waleed
2026-03-12 12:39:31 -07:00
committed by GitHub
parent 75832ca007
commit 3d5141d852
6 changed files with 2 additions and 172 deletions

View File

@@ -492,7 +492,7 @@ export const auth = betterAuth({
'google-meet',
'google-tasks',
'vertex-ai',
'github-repo',
'microsoft-dataverse',
'microsoft-teams',
'microsoft-excel',
@@ -754,83 +754,6 @@ export const auth = betterAuth({
}),
genericOAuth({
config: [
{
providerId: 'github-repo',
clientId: env.GITHUB_REPO_CLIENT_ID as string,
clientSecret: env.GITHUB_REPO_CLIENT_SECRET as string,
authorizationUrl: 'https://github.com/login/oauth/authorize',
accessType: 'offline',
prompt: 'consent',
tokenUrl: 'https://github.com/login/oauth/access_token',
userInfoUrl: 'https://api.github.com/user',
scopes: getCanonicalScopesForProvider('github-repo'),
redirectURI: `${getBaseUrl()}/api/auth/oauth2/callback/github-repo`,
getUserInfo: async (tokens) => {
try {
const profileResponse = await fetch('https://api.github.com/user', {
headers: {
Authorization: `Bearer ${tokens.accessToken}`,
'User-Agent': 'sim-studio',
},
})
if (!profileResponse.ok) {
await profileResponse.text().catch(() => {})
logger.error('Failed to fetch GitHub profile', {
status: profileResponse.status,
statusText: profileResponse.statusText,
})
throw new Error(`Failed to fetch GitHub profile: ${profileResponse.statusText}`)
}
const profile = await profileResponse.json()
if (!profile.email) {
const emailsResponse = await fetch('https://api.github.com/user/emails', {
headers: {
Authorization: `Bearer ${tokens.accessToken}`,
'User-Agent': 'sim-studio',
},
})
if (emailsResponse.ok) {
const emails = await emailsResponse.json()
const primaryEmail =
emails.find(
(email: { primary: boolean; email: string; verified: boolean }) =>
email.primary
) || emails[0]
if (primaryEmail) {
profile.email = primaryEmail.email
profile.emailVerified = primaryEmail.verified || false
}
} else {
logger.warn('Failed to fetch GitHub emails', {
status: emailsResponse.status,
statusText: emailsResponse.statusText,
})
}
}
const now = new Date()
return {
id: `${profile.id.toString()}-${crypto.randomUUID()}`,
name: profile.name || profile.login,
email: profile.email,
image: profile.avatar_url,
emailVerified: profile.emailVerified || false,
createdAt: now,
updatedAt: now,
}
} catch (error) {
logger.error('Error in GitHub getUserInfo', { error })
throw error
}
},
},
// Google providers
{
providerId: 'google-email',

View File

@@ -230,8 +230,7 @@ export const env = createEnv({
GOOGLE_CLIENT_SECRET: z.string().optional(), // Google OAuth client secret
GITHUB_CLIENT_ID: z.string().optional(), // GitHub OAuth client ID for GitHub integration
GITHUB_CLIENT_SECRET: z.string().optional(), // GitHub OAuth client secret
GITHUB_REPO_CLIENT_ID: z.string().optional(), // GitHub OAuth client ID for repo access
GITHUB_REPO_CLIENT_SECRET: z.string().optional(), // GitHub OAuth client secret for repo access
X_CLIENT_ID: z.string().optional(), // X (Twitter) OAuth client ID
X_CLIENT_SECRET: z.string().optional(), // X (Twitter) OAuth client secret
CONFLUENCE_CLIENT_ID: z.string().optional(), // Atlassian Confluence OAuth client ID

View File

@@ -170,11 +170,6 @@ describe('OAuth Token Refresh', () => {
describe('Body Credential Providers', () => {
const bodyCredentialProviders = [
{ name: 'Google', providerId: 'google', endpoint: 'https://oauth2.googleapis.com/token' },
{
name: 'GitHub',
providerId: 'github',
endpoint: 'https://github.com/login/oauth/access_token',
},
{
name: 'Microsoft',
providerId: 'microsoft',
@@ -279,19 +274,6 @@ describe('OAuth Token Refresh', () => {
)
})
it.concurrent('should include Accept header for GitHub requests', async () => {
const mockFetch = createMockFetch(defaultOAuthResponse)
const refreshToken = 'test_refresh_token'
await withMockFetch(mockFetch, () => refreshOAuthToken('github', refreshToken))
const [, requestOptions] = mockFetch.mock.calls[0] as [
string,
{ headers: Record<string, string>; body: string },
]
expect(requestOptions.headers.Accept).toBe('application/json')
})
it.concurrent('should include User-Agent header for Reddit requests', async () => {
const mockFetch = createMockFetch(defaultOAuthResponse)
const refreshToken = 'test_refresh_token'

View File

@@ -6,7 +6,6 @@ import {
CalComIcon,
ConfluenceIcon,
DropboxIcon,
GithubIcon,
GmailIcon,
GoogleBigQueryIcon,
GoogleCalendarIcon,
@@ -340,21 +339,6 @@ export const OAUTH_PROVIDERS: Record<string, OAuthProviderConfig> = {
},
defaultService: 'outlook',
},
github: {
name: 'GitHub',
icon: GithubIcon,
services: {
github: {
name: 'GitHub',
description: 'Manage repositories, issues, and pull requests.',
providerId: 'github-repo',
icon: GithubIcon,
baseProviderIcon: GithubIcon,
scopes: ['repo', 'user:email', 'read:user', 'workflow'],
},
},
defaultService: 'github',
},
x: {
name: 'X',
icon: xIcon,
@@ -988,19 +972,6 @@ function getProviderAuthConfig(provider: string): ProviderAuthConfig {
useBasicAuth: false,
}
}
case 'github': {
const { clientId, clientSecret } = getCredentials(
env.GITHUB_CLIENT_ID,
env.GITHUB_CLIENT_SECRET
)
return {
tokenEndpoint: 'https://github.com/login/oauth/access_token',
clientId,
clientSecret,
useBasicAuth: false,
additionalHeaders: { Accept: 'application/json' },
}
}
case 'x': {
const { clientId, clientSecret } = getCredentials(env.X_CLIENT_ID, env.X_CLIENT_SECRET)
return {

View File

@@ -15,8 +15,6 @@ export type OAuthProvider =
| 'google-groups'
| 'google-meet'
| 'vertex-ai'
| 'github'
| 'github-repo'
| 'x'
| 'confluence'
| 'airtable'
@@ -64,7 +62,6 @@ export type OAuthService =
| 'google-groups'
| 'google-meet'
| 'vertex-ai'
| 'github'
| 'x'
| 'confluence'
| 'airtable'

View File

@@ -66,11 +66,6 @@ describe('getAllOAuthServices', () => {
it.concurrent('should include single-service providers', () => {
const services = getAllOAuthServices()
const githubService = services.find((s) => s.providerId === 'github-repo')
expect(githubService).toBeDefined()
expect(githubService?.name).toBe('GitHub')
expect(githubService?.baseProvider).toBe('github')
const slackService = services.find((s) => s.providerId === 'slack')
expect(slackService).toBeDefined()
expect(slackService?.name).toBe('Slack')
@@ -145,14 +140,6 @@ describe('getServiceByProviderAndId', () => {
expect(service.name).toBe('Microsoft Excel')
})
it.concurrent('should work with single-service providers', () => {
const service = getServiceByProviderAndId('github')
expect(service).toBeDefined()
expect(service.providerId).toBe('github-repo')
expect(service.name).toBe('GitHub')
})
it.concurrent('should include scopes in returned service config', () => {
const service = getServiceByProviderAndId('google', 'gmail')
@@ -182,12 +169,6 @@ describe('getProviderIdFromServiceId', () => {
expect(providerId).toBe('outlook')
})
it.concurrent('should return correct providerId for GitHub', () => {
const providerId = getProviderIdFromServiceId('github')
expect(providerId).toBe('github-repo')
})
it.concurrent('should return correct providerId for Microsoft Excel', () => {
const providerId = getProviderIdFromServiceId('microsoft-excel')
@@ -262,14 +243,6 @@ describe('getServiceConfigByProviderId', () => {
expect(excelService?.name).toBe('Microsoft Excel')
})
it.concurrent('should work for GitHub', () => {
const service = getServiceConfigByProviderId('github-repo')
expect(service).toBeDefined()
expect(service?.providerId).toBe('github-repo')
expect(service?.name).toBe('GitHub')
})
it.concurrent('should work for Slack', () => {
const service = getServiceConfigByProviderId('slack')
@@ -338,14 +311,6 @@ describe('getCanonicalScopesForProvider', () => {
expect(excelScopes).toContain('Files.Read')
})
it.concurrent('should return scopes for GitHub', () => {
const scopes = getCanonicalScopesForProvider('github-repo')
expect(scopes.length).toBeGreaterThan(0)
expect(scopes).toContain('repo')
expect(scopes).toContain('user:email')
})
it.concurrent('should handle providers with empty scopes array', () => {
const scopes = getCanonicalScopesForProvider('notion')
@@ -397,13 +362,6 @@ describe('parseProvider', () => {
expect(teamsConfig.featureType).toBe('microsoft-teams')
})
it.concurrent('should parse GitHub provider', () => {
const config = parseProvider('github-repo' as OAuthProvider)
expect(config.baseProvider).toBe('github')
expect(config.featureType).toBe('github')
})
it.concurrent('should parse Slack provider', () => {
const config = parseProvider('slack' as OAuthProvider)