import type { OAuth2Adapter, OAuth2UserInfo } from "adminforth"; import type { GithubEmail } from "./types.js"; export default class AdminForthAdapterGithubOauth2 implements OAuth2Adapter { private clientID: string; private clientSecret: string; constructor(options: { clientID: string; clientSecret: string; }) { this.clientID = options.clientID; this.clientSecret = options.clientSecret; } getAuthUrl(): string { const params = new URLSearchParams({ client_id: this.clientID, scope: 'user:email read:user', allow_signup: 'true', provider: this.constructor.name }); const url = `https://github.com/login/oauth/authorize?${params.toString()}`; return url; } async getTokenFromCode(code: string, redirect_uri: string): Promise { // Exchange code for token const tokenResponse = await fetch('https://github.com/login/oauth/access_token', { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, body: JSON.stringify({ code, client_id: this.clientID, client_secret: this.clientSecret, redirect_uri, }), }); const tokenData = await tokenResponse.json(); if (tokenData.error) { console.error('Token error:', tokenData); throw new Error(tokenData.error_description || tokenData.error); } // Get user info using access token const userResponse = await fetch('https://api.github.com/user', { headers: { 'Authorization': `Bearer ${tokenData.access_token}`, 'Accept': 'application/vnd.github.v3+json' }, }); const userData = await userResponse.json(); if (userData.error) { throw new Error(userData.error_description || userData.error); } // If email is not public, fetch email separately if (!userData.email) { const emailResponse = await fetch('https://api.github.com/user/emails', { headers: { 'Authorization': `Bearer ${tokenData.access_token}`, 'Accept': 'application/vnd.github.v3+json' }, }); const emails: GithubEmail[] = await emailResponse.json(); const primaryEmail = emails.find((email: GithubEmail) => email.primary); userData.email = primaryEmail?.email; } return { provider: this.constructor.name, subject: `${userData.id}`, email: userData.email, profilePictureUrl: userData.avatar_url, fullName: userData.name }; } getName(): string { return 'GitHub'; } getIcon(): string { return ``; } }