Next.js Discord

Discord Forum

if user not logged in, dont peek the content

Answered
Alaska pollock posted this in #help-forum
Open in Discord
Avatar
Alaska pollockOP
Yo, so Im really new to next.js and I want to know how can I redirect the user to the login page if the user isnt logged in without it peeking the returned content. This works, However, I just want to know if there another clean way to do it.
Code:
c++
const [userData, setUserData] = useState<UserData | null>(null);

  const redirectToLogin = () => {
    router.push("/login");
  };

  useEffect(() => {
    const fetchUserData = () => {
      axios
        .get("http://localhost:3001/profile", { withCredentials: true })
        .then((response) => {
          setUserData(response.data.user);
        })
        .catch((error) => {
          // if not logged in redirect to login.
          redirectToLogin();
        });
    };

    fetchUserData();
  }, []);

  if (userData === null) {
    return null;
  }

  return (
    <div className="grid grid-cols-1 gap-2">
      // stuff
    </div>
  );

I know, its because of it sending an api request. Well, I can just check if theres a sessionid in the cookies but how would I check if its expired or not. Is this idea?
Answered by B33fb0n3
import { NextResponse } from 'next/server'
 // basic middleware
export function middleware(request) {

// any "is this user authenticated method"
     const session:session = await fetch(`${process.env.serverURL}/api/auth/session`, {
    headers:headers(),
    // cache: "no-store"
  })
  .then( async( res ) => await res.json() );

  const loggedIn = Object.keys(session).length > 0? true :false;
  const pathname = request.nextUrl.pathname;

// redirect, when not logged in
  if ( pathname != "/admin/login" && !loggedIn ){
    return NextResponse.redirect( new URL( '/admin/login', process.env.serverURL ) );
  }

// doing nothing, when logged in
}

@Alaska pollock This is just an example. You need to change the methods to check if the user is authenticated or not
View full answer

99 Replies

Avatar
B33fb0n3
@Alaska pollock you can use a middleware, to not let the user peak the content. You can find more about it here: https://nextjs.org/docs/app/building-your-application/routing/middleware
Avatar
Alaska pollockOP
like this, you mean?
c++
app.get('/profile', authenticateToken,...

Cuz I do.
or does it have to be a middleware.ts?
Avatar
B33fb0n3
yea, you need to create the middleware.ts and check it inside it. When he's authenticated, then don't do anything with the request you get in the middleware and when he's not logged in, redirect him to the sign in/up page. The middleware will be executed, before your page.js will be executed @Alaska pollock
Avatar
Alaska pollockOP
Okay so wait, basically then I'll send two requests (to the same api). one in the middle ware that'll check the token the api will return the users information then re-send the request in the page.tsx. is this ideal to do?
Avatar
B33fb0n3
you don't need to resend something. You can just let your code end. The "is the user authenticated"-stuff inside your page.js will be removed, because you check that inside your middleware
Avatar
Alaska pollockOP
example?
Avatar
B33fb0n3
import { NextResponse } from 'next/server'
 // basic middleware
export function middleware(request) {

// any "is this user authenticated method"
     const session:session = await fetch(`${process.env.serverURL}/api/auth/session`, {
    headers:headers(),
    // cache: "no-store"
  })
  .then( async( res ) => await res.json() );

  const loggedIn = Object.keys(session).length > 0? true :false;
  const pathname = request.nextUrl.pathname;

// redirect, when not logged in
  if ( pathname != "/admin/login" && !loggedIn ){
    return NextResponse.redirect( new URL( '/admin/login', process.env.serverURL ) );
  }

// doing nothing, when logged in
}

@Alaska pollock This is just an example. You need to change the methods to check if the user is authenticated or not
Answer
Avatar
Alaska pollockOP
how would it look from the login componenet?
Avatar
B33fb0n3
that's the middleware and you don't need to change it dependently on the requested path. The middleware.ts is a different file
Avatar
Alaska pollockOP
so I dont import?
then how would i get the response?
Avatar
B33fb0n3
maybe you understand it a little better with this self made image lol ^^
Image
Avatar
Alaska pollockOP
Uh I know what middle ware is and how it works, I just want to know how do I send the response to the login component?
or access it
Avatar
B33fb0n3
what kind of response? the client get's the response. Not your components 🙂
Avatar
Alaska pollockOP
Yes but I would like to access it
Avatar
B33fb0n3
what would you like to do? What is the goal?
Avatar
Alaska pollockOP
id like to print the users data from the database which is recieved from the api itself, And i have a middleware for every after-login apis which checks the jwt token validation
Avatar
B33fb0n3
You can change the response from the middleware and return json. This json can be read and displayed
Avatar
Alaska pollockOP
could you provide an example?
const fetchUserData = () => {
axios
.get("http://localhost:3001/profile", { withCredentials: true })
.then((response) => {
setUserData(response.data.user);
})
.catch((error) => {
redirectToLogin();
});
};

here i want to call the function setUserData
Avatar
Forster's Tern
Can anyone point me in the right direction for handling checkout/order calculation via api endpoints? Using latest app router and not using a db. Just localstorage for now
Avatar
Alaska pollockOP
bruh
#help-forum
Avatar
Forster's Tern
Thx. Not sure how I posted in here by accident. Barely use discord
return Response.json(
      { success: false, message: 'authentication failed' },
      { status: 401 }
    )

Here you can share your data to the client
Avatar
Alaska pollockOP
and how would I go ahead to access it from the client?
I also appreciate your help <3
Avatar
B33fb0n3
that's then the page. It's like if you ask a api. Then it's just data. Take a look at this page: https://dummyjson.com/products
It's also just data 🙂
Avatar
Alaska pollockOP
middleware:
c++
import { NextRequest } from 'next/server'
import { NextResponse } from 'next/server'
import axios from "axios";
 
export const config = {
  matcher: '/dashboard',
}
 
export function middleware(request: NextRequest) {
    axios
    .get("http://localhost:3001/profile", { withCredentials: true })
    .then((response) => {
        return Response.json(response);
    })
    .catch(() => {
        return NextResponse.redirect(new URL('/login', request.url));
    });
}


Dashboard:
c++
const [userData, setUserData] = useState<UserData | null>(null);


One last question, how would I go and set "userData" to the middleware response
@B33fb0n3
Avatar
B33fb0n3
if you really want to show the user the data I know only one way: fetch the url first. If you get json, render the json, if not, redirect the user. When I would be you, I would redirect him to the sign up/in page or if it's another not handled error, create a error log and redirect the user to a new site with the specific error id. Fetch the error id serverside and render it for the user. That's what I would do, when I would be you
Avatar
Alaska pollockOP
I do fetch the user information, However, Its peeking the page first while the request is being sent.
Avatar
B33fb0n3
it can't peek, when you use middleware and redirect the client, because the middleware is executed and completely ended BEFORE the page.js
Avatar
Alaska pollockOP
Well, I dont know how to send the response to the client
yup, I want to send the response to the client
from middleware to client if thats possible, otherwise ill be sending two http requests which isnt ideal
Avatar
Alaska pollockOP
@B33fb0n3
Avatar
B33fb0n3
Avatar
Alaska pollockOP
Okay thats good, But if the jwt token is valid it returns the users information, and if i "get the json" how would the client read it?
do you see now, if its not yes i can redirect without it peeking, However, I cant display content if the json is there correctly
@B33fb0n3
Avatar
B33fb0n3
in your example your middleware should only say if the user should able to see the content from your page. So the middleware checks

"is jwt valid"
|> yes: let the request through
|> no: redirect to login.
If the user pass the check and will get to the requested page, you can fetch the userdata on the page
Avatar
Alaska pollockOP
so i need to send two requests,
1. to check the jwt token
2. to fetch the user data
Avatar
B33fb0n3
The jwt check should only be a jwt check and not a fetch userdata when jwt is valid
Avatar
Alaska pollockOP
Yup that was I was saying.
or I can do that too, i guess?
c++
const [userData, setUserData] = useState<UserData | null>(null);

  useEffect(() => {
    const fetchUserData = () => {
      axios
        .get("http://localhost:3001/profile", { withCredentials: true })
        .then((response) => {
          setUserData(response.data.user);
        })
        .catch(() => {
          redirectToLogin();
        });
    };

    fetchUserData();
  }, []);

  if (userData === null) {
    return null;
  }
if (userData === null) {
return null;
}
Avatar
B33fb0n3
???
Avatar
Alaska pollockOP
what?
itll return null so they cant see the content
its like a waiting thing until they're redirected.
Avatar
B33fb0n3
that doesn't make any sense...
this is on your page.js?
Avatar
Alaska pollockOP
damn it, ill just use express sessions
yes
jwt = pain, for me, atleast.
anyways, Appreciate the help
<3 !!
Avatar
B33fb0n3
I thought I visulized it good enough. Just to get this right: The middleware will be exectued BEFORE the page.js loads. So if you check in the middleware if he's auth. and maybe redirect him then to a public page, your requested page.js will NEVER been shown. So you can remove all the other stuff and just imagine that there is a user anytime
jwt is fairly easy if we understood this topic
Avatar
Alfonsus Ardani
this can be done in single request since jwt token are stored in cookies and you can check the cookies before fetching the user data
Avatar
Alaska pollockOP
Yup, But I cant check the validation of it.
without sending an api request to the server to do so.
Avatar
Alfonsus Ardani
your auth server is detached from Next.js backend?
Avatar
Alaska pollockOP
wdym? i use node.js & express
Avatar
Alfonsus Ardani
so it is separate from next.js backend
does the data fetching also separate from next.js backend and your auth server?
Avatar
Alaska pollockOP
ig
Avatar
Alfonsus Ardani
so your auth server and your data server is different?
well then 2 requests are necessary then :v
Avatar
Alaska pollockOP
So, wait how do I do it un-seperate from the front-end?
@B33fb0n3
Avatar
Alaska pollockOP
@Alfonsus Ardani
Avatar
Alfonsus Ardani
Implement the auth verification logic in next.js instead of at ur custom express backend
Avatar
Alaska pollockOP
and how should my front-end code look like?
Avatar
Alaska pollockOP
@Alfonsus Ardani
Avatar
Alfonsus Ardani
const data = await fetchdata()
@Alaska pollock
Avatar
Alaska pollockOP
could you provide me with an example from github or sum?
Avatar
Alfonsus Ardani
i dont have one thats readily available right now
but you can just hit fetchdata() and authenticate inside that function directly
Avatar
Alaska pollockOP
okay, thanks!
Avatar
Eric Burel
Securing in middleware can sometimes be tricky because you are limited to the edge runtime
not that you can also check authentication at page level by turning the page into a React server component
doing page level security at the middleware level is kind of the "grail", because it allows for static personalization without dynamic per-request rendering
if you can achive that, that's awesome
but sometimes, you need to get the current user from the database (session based auth) or have a way to invalidate JWT that relies on a database => you can't connect via TCP ("normal" long running db client you have in Node.js code) so you have to have an HTTP interface to your db
this explains why services like Upstash are getting popular: you can use Redis with fetch calls, so it works in middleware
but it's not really the norm yet and not super mature, for instance I had to raise an issue in upstash client that made it incompatible with static rendering until recently
Avatar
Alaska pollockOP
THANK YOU!!! EXACTLY WHAT I WANTED <333@Eric Burel
Avatar
Eric Burel
This dates from earlier version of next so not updated to the app router
Maybe take a look at the devographics code I've shared, it has authentication using passport and pages are protected (you cannot peek a user response without being logged and owning this response)
That's a big app but shows a complete setup
Avatar
Alaska pollockOP
whats being used for the back-end?