import axios from 'axios'; import { prisma } from "~/db.server"; import { createUserSession } from '~/session.server'; export interface DiscordUser { id: string; username: string; discriminator: string; avatar: string; bot?: boolean; system?: boolean; mfa_enabled?: boolean; } export interface AccessTokenResponse { access_token: string; expires: number; refresh_token: string; } export function getAccessToken(code: string): Promise { return new Promise( (resolve, reject) => { const body = new FormData(); body.append("grant_type", "authorization_code"); body.append("code", code); body.append("redirect_url", process.env.DISCORD_REDIRECT_URI || ""); axios.post("https://discord.com/api/oauth2/token", body) .then((res) => { const { access_token, refresh_token, expires_in } = res.data; resolve({ access_token, refresh_token, expires: Date.now() + expires_in * 1000 }); }) .catch(reject); } ) } export async function authorize(access_code: string): Promise { return new Promise( (resolve, reject) => { const formData = new FormData(); formData.append("client_id", process.env.DISCORD_CLIENT_ID || ""); formData.append("client_secret", process.env.DISCORD_CLIENT_SECRET || ""); formData.append("grant_type", "authorization_code"); formData.append("redirect_uri", process.env.DISCORD_REDIRECT_URI || ""); formData.append("scope", "identify"); formData.append("code", access_code); axios.post("https://discord.com/api/oauth2/token", formData) .then((res) => { const { access_token, refresh_token, expires_in } = res.data; resolve({ access_token, refresh_token, expires: Date.now() + expires_in * 1000 }); }) .catch(reject); } ) } export function getDiscordUser(token: string): Promise { return new Promise( (resolve, reject) => { axios.get("https://discord.com/api/users/@me", { headers: { Authorization: `Bearer ${token}` } }) .then( (res) => { resolve(res.data); } ) .catch(reject); } ) } export async function discordLogin(request: Request, code: string): Promise { return new Promise( (resolve, reject) => { getAccessToken(code) .then((token) => { getDiscordUser(token.access_token) .then(async (user) => { prisma.discordUser.upsert({ create: { discord_id: user.id, access_token: token.access_token, refresh_token: token.refresh_token, expires: new Date(token.expires), username: user.username, discriminator: user.discriminator, }, update: { discord_id: user.id, access_token: token.access_token, refresh_token: token.refresh_token, expires: new Date(token.expires), username: user.username, discriminator: user.discriminator, }, where: { discord_id: user.id } }) .then(async () => { resolve(await createUserSession({request, discord_id: user.id, redirectTo: '/'})); }) }) }) } ) }