I'm totally stuck on next auth infinitely looping on my next project. We recently made the main page of the app the defacto "home" page so I updated that page's name to index.tsx making it root. ever since then its like it gets trapped in this redirect hell. I have absolutely no idea what I'm doing wrong.
its worth noting our app doesn't have a sign on page perse but rather you're redirected to Okta's SSO flow. All recomendations I found for handling this use case said to create a signin.tsx which basically just tests session status then either calls the sign in function for Okta or redirects you to '/'. then in pages/index I've had a redirect also directing you to 'auth/signin' which docs have said to do in order to protect certain routes. but even without that bit of code in the getServerSideProps it STILL infinitely loops. I feel like its too much complexity? can someone who has a clue help me thin some of this out? what don't I need?
[...NEXTAUTH]
export const authOptionsFunction = (): AuthOptions => {
return {
providers: [
Okta({
//@ts-ignore
clientId: process.env.OKTA_OAUTH2_CLIENT_ID as string,
//@ts-ignore
clientSecret: Config.OKTA_OAUTH2_CLIENT_SECRET as string,
//@ts-ignore
issuer: process.env.OKTA_OAUTH2_ISSUER as string,
// clientId: process.env.OKTA_OAUTH2_CLIENT_ID as string,
// clientSecret: process.env.OKTA_OAUTH2_CLIENT_SECRET as string,
// issuer: process.env.OKTA_OAUTH2_ISSUER as string,
})
],
//@ts-ignore
secret: process.env.NEXTAUTH_SECRET,
//secret: process.env.NEXTAUTH_SECRET as string,
session: { strategy: 'jwt'},
callbacks: {
async jwt({ token, account }: any) {
if (account) {
token.accessToken = account.access_token;
token.idToken = account.id_token;
token.oktaId = account.providerAccountId
}
var tokenParsed = JSON.parse(Buffer.from(token.accessToken.split('.')[1], 'base64').toString());
const dateNowInSeconds = new Date().getTime() / 1000
if (dateNowInSeconds > tokenParsed.exp) {
throw Error("expired Okta access token");
}
return token;
},
async session({ session, token }: any) {
// get our native current user data here
const res = await GET_CURRENT_USER(token);
const { data } = await res.json();
session.accessToken = token.accessToken;
session.idToken = token.idToken;
session.oktaId = token.oktaId;
session.currentUser = data;
return session;
},
async signIn({ user, account, profile, email, credentials}) {
return true;
},
async redirect({ url, baseUrl }) {
// Allows relative callback URLs
if (url.startsWith("/")) return `${baseUrl}${url}`
// Allows callback URLs on the same origin
else if (new URL(url).origin === baseUrl) return url
return baseUrl
}
},
debug: process.env.NODE_ENV === 'development',
pages: {
signIn: "/auth/signin",
},
}
}
export const authOptions: NextAuthOptions = authOptionsFunction()
export default NextAuth(authOptions);
MIDDLEWARE
export default withAuth(
(req: NextRequest & { nextauth: { token: JWT | null } }) => {
if (req.nextUrl.pathname.startsWith('/auth') || req.nextUrl.pathname.startsWith('/_next')) {
return NextResponse.next();
}
// if there is no session
if (!req.nextauth.token) {
req.nextUrl.pathname = '/auth/signin';
return NextResponse.redirect(req.nextUrl);
}
return NextResponse.next();
},
{
callbacks: {
authorized() {
return true
},
},
pages: {
signIn: "/auth/signin",
},
}
);
SIGN IN COMPONENT
const SignIn = () => {
const { status } = useSession();
const router = useRouter();
React.useEffect(() => {
if (status === 'unauthenticated') {
signIn('okta');
} else if (status === 'authenticated') {
router.push('/');
}
}, [status]);
return (
<>
</>
)
}
export default SignIn;
**PAGES / INDEX **
this little bit is just a part of getServerSideProps - the rest of the page is just a standard Page, ya know? fetch the props, pass the props, use the props.
if (!session) {
return {
redirect: {
destination: '/auth/signin',
permanent: false,
}
}
}