Next.js Discord

Discord Forum

redirect() not working from inside server api route

Answered
Cinnamon posted this in #help-forum
Open in Discord
CinnamonOP
Most of my api routes call this getCurrentUser method. if the cookie is expired, it's should redirect the user to the sign-in page. This was working but now its stopped working (didnt make any changes to it)

  export async function getCurrentUser() {
    await initAdmin();
    const auth = getAuth();
    
    const session = await getSession();
  
    if (!(await isUserAuthenticated(session))) {
      console.log('++ Not authenticated')
      redirect('/sign-in');
    }

    const decodedIdToken = await auth.verifySessionCookie(session!);
    const currentUser = await auth.getUser(decodedIdToken.uid);
  
    return currentUser;
  }


the output shows the log statement, but no redirect is happening

  errorInfo: {
    code: 'auth/session-cookie-expired',
    message: 'Firebase session cookie has expired. Get a fresh session cookie from your client app and try again (auth/session-cookie-expired). See https://firebase.google.com/docs/auth/admin/manage-cookies for details on how to retrieve a session cookie.'
  },
  codePrefix: 'auth'
}
++ Not authenticated
 POST /api/canon/create 307 in 312ms
 ✓ Compiled /sign-in in 302ms (1999 modules)
Registered firebase app.
 POST /sign-in 200 in 581ms
Answered by joulev
for the case of the api route, it is basically like this

you do
fetch("/api/foo")

in the api route, redirect("/hello")
nextjs caught the redirect() call, producing a redirect response to "/hello" for that api route

your fetch then becomes equivalent to
fetch("/hello")

and as you already know, fetch("/hello") doesn't redirect anyone to anything. you simply get the html of /hello.
View full answer

12 Replies

CinnamonOP
GetCurrentUser is a function inside lib. It’s being called from insider a server api route
CinnamonOP
for sure, here's /api/canon/create/route.ts
// src/app/api/canon/create/route.ts

import { getCurrentUser } from '@/lib/firebase/server/auth';
import { initAdmin } from '@/lib/firebase/server/init';
import { Canon } from '@/lib/models/Canon';
import { FieldValue, getFirestore } from 'firebase-admin/firestore';
import { NextRequest, NextResponse } from 'next/server';

// import { APIResponse } from "@/types";

type CreateTeamRequestBody = {
  teamId: string;
  canon: Canon
};

export async function POST(request: NextRequest) {
  const user = await getCurrentUser();

  if (!user) {
    return NextResponse.json({
      success: false,
      data: 'User not authenticated.'
    });
  }
  const { uid } = user;
  const reqBody = (await request.json()) as CreateTeamRequestBody;
  const { teamId, canon } = reqBody;

  await initAdmin();
  const firestore = getFirestore();
  const canonRef = firestore.collection('canons');

  const response = await canonRef.add({
    ...canon,
    teamId,
    createdBy: uid,
    visibleTo: [teamId],
    createdAt: FieldValue.serverTimestamp(),
    updatedAt: FieldValue.serverTimestamp()
  });

  console.log('Canon created with ID: ', response.id);

  return NextResponse.json<any>({
    success: true,
    data: {canonId: response.id}
  });
}
thats odd
CinnamonOP
I see, can you explain the ways in which it works unexpectedly?
Is there a recommended way of triggering a redirect? I prefer not to have to handle authentication errors back inside every api call inside my app. Middleware recommended for that?
for the case of the api route, it is basically like this

you do
fetch("/api/foo")

in the api route, redirect("/hello")
nextjs caught the redirect() call, producing a redirect response to "/hello" for that api route

your fetch then becomes equivalent to
fetch("/hello")

and as you already know, fetch("/hello") doesn't redirect anyone to anything. you simply get the html of /hello.
Answer
if you go to /api/foo in the browser directly, you will be redirected to /hello normally
but here you fetch() it rather than going by the browser url bar, so the redirect doesn't happen in the frontend
CinnamonOP
Thanks everyone! Much appreciated 🙏
@Cinnamon Is there a recommended way of triggering a redirect? I prefer not to have to handle authentication errors back inside every api call inside my app. Middleware recommended for that?
for this one i prefer middleware yep. or checking auth in layout (but beware that the method of checking auth in layout has a [gotcha](https://github.com/eric-burel/securing-rsc-layout-leak) to be mindful of)

if you want to redirect after the user does something, use server action. redirect() calls in server actions will be passed to the frontend router which will handle the redirect normally