Skip to content

Commit 0fd911c

Browse files
committed
add redirects
1 parent 1f201b9 commit 0fd911c

File tree

4 files changed

+100
-13
lines changed

4 files changed

+100
-13
lines changed

frontend/src/pages/api/auth/[...nextauth].ts

Lines changed: 76 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import prisma from "@/lib/prisma/prisma";
22
import { PrismaAdapter } from "@next-auth/prisma-adapter";
3-
import NextAuth, { SessionStrategy } from "next-auth";
3+
import NextAuth, { Session, TokenSet, User } from "next-auth";
44
import GoogleProvider from "next-auth/providers/google";
55

66
declare module "next-auth" {
@@ -31,15 +31,82 @@ export const getAuthOptions = () => {
3131
pages: {
3232
signIn: "/auth/signin",
3333
},
34-
session: {
35-
strategy: "jwt" as SessionStrategy,
36-
},
37-
jwt: {
38-
// The maximum age of the NextAuth.js issued JWT in seconds.
39-
// Defaults to `session.maxAge`.
40-
maxAge: 60 * 60 * 24 * 30,
41-
},
4234
adapter: PrismaAdapter(prisma),
35+
callbacks: {
36+
async session({ session, user }: { session: Session; user: User }) {
37+
const [google] = await prisma.account.findMany({
38+
where: { userId: user.id, provider: "google" },
39+
});
40+
if (
41+
google.expires_at !== null &&
42+
google.refresh_token !== null &&
43+
google.expires_at * 1000 < Date.now()
44+
) {
45+
// If the access token has expired, try to refresh it
46+
try {
47+
const googleClientSecret = process.env.GOOGLE_CLIENT_SECRET;
48+
const googleClientId = process.env.GOOGLE_CLIENT_ID;
49+
if (
50+
googleClientSecret === undefined ||
51+
googleClientId === undefined
52+
) {
53+
throw new Error("Missing Google client secret or client id");
54+
}
55+
// https://accounts.google.com/.well-known/openid-configuration
56+
// We need the `token_endpoint`.
57+
const response = await fetch(
58+
"https://oauth2.googleapis.com/token",
59+
{
60+
headers: {
61+
"Content-Type": "application/x-www-form-urlencoded",
62+
},
63+
body: new URLSearchParams({
64+
client_id: googleClientId,
65+
client_secret: googleClientSecret,
66+
grant_type: "refresh_token",
67+
refresh_token: google.refresh_token,
68+
}),
69+
method: "POST",
70+
}
71+
);
72+
73+
const tokens: TokenSet = (await response.json()) as TokenSet;
74+
75+
if (!response.ok) throw tokens;
76+
77+
if (
78+
tokens.expires_in === undefined ||
79+
tokens.expires_in === null ||
80+
typeof tokens.expires_in !== "number"
81+
) {
82+
throw new Error("Missing expires_in");
83+
}
84+
const newExpiresAt = Math.floor(
85+
Date.now() / 1000 + tokens.expires_in
86+
);
87+
88+
await prisma.account.update({
89+
data: {
90+
access_token: tokens.access_token,
91+
expires_at: newExpiresAt,
92+
refresh_token: tokens.refresh_token ?? google.refresh_token,
93+
},
94+
where: {
95+
provider_providerAccountId: {
96+
provider: "google",
97+
providerAccountId: google.providerAccountId,
98+
},
99+
},
100+
});
101+
} catch (error) {
102+
console.error("Error refreshing access token", error);
103+
// The error property will be used client-side to handle the refresh token error
104+
session.error = "RefreshAccessTokenError";
105+
}
106+
}
107+
return session;
108+
},
109+
},
43110
};
44111
return options;
45112
};

frontend/src/pages/auth/signin.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,6 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
5454
getAuthOptions()
5555
);
5656

57-
// If the user is already logged in, redirect.
58-
// Note: Make sure not to redirect to the same page
59-
// To avoid an infinite loop!
6057
if (session !== null) {
6158
return { redirect: { destination: "/query" } };
6259
}

frontend/src/pages/index.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ import { IndexHeader } from "@/components/page/index/IndexHeader";
33
import { CHAKRA_100VH } from "@/style/constants";
44
import { Flex } from "@chakra-ui/react";
55

6+
import type { GetServerSidePropsContext } from "next";
7+
import { getServerSession } from "next-auth/next";
8+
import { getProviders } from "next-auth/react";
9+
import { getAuthOptions } from "./api/auth/[...nextauth]";
10+
611
export default function Home() {
712
return (
813
<Flex direction={"column"} h={CHAKRA_100VH}>
@@ -19,3 +24,21 @@ export default function Home() {
1924
</Flex>
2025
);
2126
}
27+
28+
export async function getServerSideProps(context: GetServerSidePropsContext) {
29+
const session = await getServerSession(
30+
context.req,
31+
context.res,
32+
getAuthOptions()
33+
);
34+
35+
if (session !== null) {
36+
return { redirect: { destination: "/query" } };
37+
}
38+
39+
const providers = await getProviders();
40+
41+
return {
42+
props: { providers: providers ?? [] },
43+
};
44+
}

frontend/src/pages/query.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
113113
// If the user is already logged in, redirect.
114114
// Note: Make sure not to redirect to the same page
115115
// To avoid an infinite loop!
116-
if (session !== null) {
116+
if (session === null) {
117117
return { redirect: { destination: "/" } };
118118
}
119119

0 commit comments

Comments
 (0)