icns-frontend/pages/api/twitter-auth-info.ts

152 lines
3.9 KiB
TypeScript
Raw Normal View History

2022-12-23 13:30:35 +00:00
import { captureException } from "@sentry/nextjs";
2022-12-05 10:50:13 +00:00
import { withIronSessionApiRoute } from "iron-session/next";
2022-12-23 13:30:35 +00:00
import type { NextApiRequest, NextApiResponse } from "next";
2022-12-05 11:01:24 +00:00
import { twitterApiBaseUrl } from "../../constants/twitter";
2022-12-23 13:30:35 +00:00
import { ironOptions } from "../../iron.config";
2022-11-30 09:58:19 +00:00
2022-12-05 10:50:13 +00:00
export default withIronSessionApiRoute(async function handler(
2022-11-30 09:58:19 +00:00
req: NextApiRequest,
2022-11-30 14:55:17 +00:00
res: NextApiResponse,
2022-11-30 09:58:19 +00:00
) {
2022-12-05 11:01:24 +00:00
if (
!process.env.TWITTER_CLIENT_ID ||
!process.env.TWITTER_CLIENT_SECRET ||
!process.env.TWITTER_AUTH_CALLBACK_URI
) {
console.error(new Error(".env is not set"));
return res.status(500).send({
error:
2022-12-05 11:01:24 +00:00
"Twitter app client id or client secret or callback URI is not set",
});
2022-12-05 11:01:24 +00:00
}
2022-12-05 10:50:13 +00:00
2022-12-05 11:01:24 +00:00
if (!req.session.code_verifier) {
return res.status(401).send({
error: "No OAuth2.0 code verifier",
});
2022-12-05 11:01:24 +00:00
}
2022-12-05 10:50:13 +00:00
2022-12-05 11:01:24 +00:00
try {
const params = new URLSearchParams();
if (req.session.refresh_token) {
params.append("grant_type", "refresh_token");
params.append("refresh_token", req.session.refresh_token);
params.append("client_id", process.env.TWITTER_CLIENT_ID);
} else {
const { code, state } = req.query;
if (state !== process.env.TWITTER_AUTH_STATE) {
return res.status(401).send({ error: "State isn't matching" });
}
params.append("grant_type", "authorization_code");
params.append("code", code as string);
params.append("redirect_uri", process.env.TWITTER_AUTH_CALLBACK_URI);
params.append("code_verifier", req.session.code_verifier);
2022-11-30 09:58:19 +00:00
}
2022-12-05 10:50:13 +00:00
2022-12-23 13:30:35 +00:00
const {
access_token: accessToken,
refresh_token,
2022-12-26 09:03:54 +00:00
error: authTokenErrorTitle,
error_description: authTokenErrorDesc,
2022-12-23 13:30:35 +00:00
}: TwitterOAuth2TokenResponse = await (
await fetch(`${twitterApiBaseUrl}/oauth2/token`, {
method: "post",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
Authorization: `Basic ${Buffer.from(
`${process.env.TWITTER_CLIENT_ID}:${process.env.TWITTER_CLIENT_SECRET}`,
).toString("base64")}`,
2022-12-05 10:50:13 +00:00
},
2022-12-23 13:30:35 +00:00
body: params,
})
).json();
2022-12-26 09:03:54 +00:00
if (authTokenErrorTitle) {
throw new Error(`${authTokenErrorTitle}: ${authTokenErrorDesc}`);
}
req.session.refresh_token = refresh_token;
await req.session.save();
2022-12-26 09:03:54 +00:00
const {
data,
title: usersMeErrorTitle,
detail: usersMeErrorDesc,
}: TwitterUsersMeResponse = await (
2022-12-23 13:30:35 +00:00
await fetch(
`${twitterApiBaseUrl}/users/me?user.fields=profile_image_url,public_metrics,description`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
},
},
2022-12-23 13:30:35 +00:00
)
).json();
2022-12-26 09:03:54 +00:00
if (usersMeErrorTitle) {
throw new Error(`${usersMeErrorTitle}: ${usersMeErrorDesc}`);
}
2022-12-23 13:30:35 +00:00
const {
id,
username,
name,
profile_image_url,
description,
public_metrics,
} = data || {};
2022-12-05 10:50:13 +00:00
res.status(200).json({
accessToken,
id,
username,
name,
2022-12-23 13:30:35 +00:00
profile_image_url: profile_image_url?.replace(
"normal.jpg",
"400x400.jpg",
),
description,
public_metrics,
2022-12-05 10:50:13 +00:00
});
2022-12-23 13:30:35 +00:00
} catch (error: any) {
console.error(error);
2022-12-23 13:30:35 +00:00
captureException(error);
2022-12-26 09:03:54 +00:00
res.status(500).json({ error: error.message });
2022-11-30 09:58:19 +00:00
}
2022-12-05 10:50:13 +00:00
},
ironOptions);
interface TwitterOAuth2TokenResponse {
token_type: string;
expires_in: number;
access_token: string;
scope: string;
refresh_token: string;
2022-12-26 09:03:54 +00:00
error?: string;
error_description?: string;
}
interface TwitterUsersMeResponse {
2022-12-23 13:30:35 +00:00
data?: {
id: string;
username: string;
name: string;
profile_image_url: string;
description: string;
public_metrics: TwitterPublicMetrics;
};
2022-12-23 13:30:35 +00:00
// Error data
title?: string;
detail?: string;
type?: string;
status?: string;
}
export interface TwitterPublicMetrics {
followers_count: number;
following_count: number;
listed_count: number;
tweet_count: number;
}