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 ``;
}
}