Protected routes in Nextjs?

In the past I have made protected routes using react router so that if a user is not authenticated and tries to go to a page, they are redirected to the login page and then once logged in, brought to the page they were trying to go. I’m now trying to learn Nextjs and wanna know firstly if this is the best way to ensure authentication, and also the best way to do it with Nextjs routing if it is. I’ve found varying answers online so I figured I’d ask here.
30 Replies
Samathingamajig
with next you have the power to redirect at the original request level (i.e. if a user requests /admin-panel and they're not an admin, instead of downloading all the javascript for the page, parsing it, running it, then getting redirected, nextjs can tell the browser to redirect back to /home (a name i just made up, any will work) without the browser needing to download any html or js) you would do this kind of route protection in getServerSideProps() in NextJS v12 and below, i dont know exactly how you'd do it in NextJS v13's app directory beta
T
TOP2y ago
Oh that's super cool! I'll have to look more into that. Does create-t3-app currently use NextJS 12?
Neto
Neto2y ago
Next 13 But not app dir
T
TOP2y ago
Oh ok so I would still do that in getServerSideProps then?
Neto
Neto2y ago
Yea
T
TOP2y ago
Awesome thx! I'm still totally new to next and SSR so it's definitely a learning process
Neto
Neto2y ago
Gl with the studies
T
TOP2y ago
I did see that on the t3app page it says
getServerSideProps is generally discouraged unless there is a good reason for it, due to the fact that it is a blocking call and will slow down your site. Incremental Static Regeneration↗ is a great alternative to getServerSideProps when the data is dynamic and can be fetched incrementally.
Is this case an exception to that rule?
Samathingamajig
my message was a bit misleading, Next13 is still completely backwards compatable with gSSP and that kind of stuff, the /app directory is an opt-in beta feature yes, the t3 way of doing things is getting a quick TTFB (time to first btye; the time it takes for the response to start to be sent) and loading the data via tRPC. That quote is talking about that you shouldn't use getServerSideProps if you're going to be loading data since that increases the initial loading time of the app for users. getServerSideProps can be used for checking auth
T
TOP2y ago
ahhhh ok. That makes sense
Samathingamajig
I think you can also do path-based auth blocking in the ./src/_middleware.ts file (might not exist by default, but if you do make it, nextjs will load it)
T
TOP2y ago
I don't need to do anything crazy. Just route to login for people not logged in and also block people from visiting pages they weren't invited to I'm rebuilding a project I did at the end of college, but I did it with 4 other people who had never done any web development and its all in poorly coded javascript and using firebase so I decided to just start from scratch and try to do it right
T
TOP2y ago
Should I do something like this? https://www.youtube.com/watch?v=pmAnWOofqJE
Josh tried coding
YouTube
Securely using JWT on the Edge: Authentication in NextJS Middleware!
Handling JWT-based authentication inside of NextJS middleware is super fast, and very useful but can be a bit tricky to implement. Let's look at best practises for implementing JWT auth inside of NextJS middleware, eliminating the need to call a separate API route to handle the JWT authentication. We'll also pass back the JWT from a tRPC backend...
T
TOP2y ago
He uses a JWT here Idk if that's what I want or not
Samathingamajig
from what i've seen we generally avoid jwt's in favor of session cookies that guy doesn't have a git repo in the description :/
T
TOP2y ago
yeah a bit annoying The same guy does have a video on cookies
T
TOP2y ago
Josh tried coding
YouTube
Cookies in NextJS: Easy To Learn & Super Useful!
Cookies in NextJS Middleware are super simple and yet prove to be useful in a variety of situations. Let's take a look at how to use cookies in nextjs middleware! Don't ask me what the heck that thing in the thumbnail is haha Thanks for watching and have fun implementing this knowledge into your own projects!
T
TOP2y ago
I haven't watched it yet But it might be closer to what you're talking about
bennettdev
bennettdev2y ago
I can highly recommend using Next.js' middleware instead of redirecting from getServerSideProps. Imagine you will have more pages in the future, but maybe one of them is statically generated or uses ISR (via getStaticProps) - you cannot protect static pages because you don't have a request to check on the server (like in gSSP). Middleware instead runs on the server for EVERY route, no matter if server-side rendered or statically generated. It is therefore "one place to do all". There are some examples for this, just google "middleware authentication" or "middleware protected".
T
TOP2y ago
Reviving this question to ask a follow up. I know with NextAuth I can use useSession() to really easily check to see if the user is authenticated. Can I use this in middleware like I can on a NextPage? I'm guessing the answer is going to be no And I'm gonna have to do some stuff with cookies
T
TOP2y ago
Oh? This looks promising
stanisław
stanisław2y ago
How would getServerSideProps call look like using server components? I haven't found anything related to this topic in beta nextjs docs Or is there currently no way to get request data such as cookies using server components
T
TOP2y ago
I'm not sure about that In regards to the screenshot I posted, I tried using that method and still get redirected to login even if I'm logged in with Discord for some reason
bennettdev
bennettdev2y ago
When on the server (like getServerSideProps and in the middleware), you can always use getServerAuthSession, as the session is part of the request. See: https://create.t3.gg/en/usage/next-auth#retrieving-session-server-side
Create T3 App
NextAuth.js 🚀 Create T3 App
The best way to start a full-stack, typesafe Next.js app.
T
TOP2y ago
This example is using getServerSideProps inside of a page. How would I go about doing this in middleware? Since in the example they use await in the async function and pass a context Oh wait theres another example further down I'm still getting the infinite sign in loop :/ It always redirects to sign in
c
c2y ago
also having this issue - was wondering if anyone has a middleware code example that I could look at for protecting routes. figured this out using middleware with roles if anyone else has a similar issue:
// middleware.ts

import { withAuth } from "next-auth/middleware";

// More on how NextAuth.js middleware works: https://next-auth.js.org/configuration/nextjs#middleware
export default withAuth({
callbacks: {
authorized({ req, token }) {
// `/admin` requires admin role
if (
req.nextUrl.pathname === "/dash" ||
req.nextUrl.pathname === "/dash/templates"
) {
return token?.userRole === "admin";
}
// `/me` only requires the user to be logged in
return !!token;
},
},
});

export const config = { matcher: ["/dash", "/dash/templates"] };
// middleware.ts

import { withAuth } from "next-auth/middleware";

// More on how NextAuth.js middleware works: https://next-auth.js.org/configuration/nextjs#middleware
export default withAuth({
callbacks: {
authorized({ req, token }) {
// `/admin` requires admin role
if (
req.nextUrl.pathname === "/dash" ||
req.nextUrl.pathname === "/dash/templates"
) {
return token?.userRole === "admin";
}
// `/me` only requires the user to be logged in
return !!token;
},
},
});

export const config = { matcher: ["/dash", "/dash/templates"] };
and
// [...nextauth].ts

import NextAuth, { type NextAuthOptions } from "next-auth";
import DiscordProvider from "next-auth/providers/discord";
// Prisma adapter for NextAuth, optional and can be removed
import { PrismaAdapter } from "@next-auth/prisma-adapter";

import { env } from "../../../env/server.mjs";
import { prisma } from "../../../server/db";

export const authOptions: NextAuthOptions = {
// Include user.id on session
callbacks: {
async jwt({ token }) {
console.log(token);
if (token.email === "[email protected]") {
token.userRole = "admin";
}
console.log(token.userRole);
return token;
},
},
// Configure one or more authentication providers
adapter: PrismaAdapter(prisma),
providers: [
DiscordProvider({
clientId: env.DISCORD_CLIENT_ID,
clientSecret: env.DISCORD_CLIENT_SECRET,
}),
],
session: {
strategy: "jwt",
},
};

export default NextAuth(authOptions);
// [...nextauth].ts

import NextAuth, { type NextAuthOptions } from "next-auth";
import DiscordProvider from "next-auth/providers/discord";
// Prisma adapter for NextAuth, optional and can be removed
import { PrismaAdapter } from "@next-auth/prisma-adapter";

import { env } from "../../../env/server.mjs";
import { prisma } from "../../../server/db";

export const authOptions: NextAuthOptions = {
// Include user.id on session
callbacks: {
async jwt({ token }) {
console.log(token);
if (token.email === "[email protected]") {
token.userRole = "admin";
}
console.log(token.userRole);
return token;
},
},
// Configure one or more authentication providers
adapter: PrismaAdapter(prisma),
providers: [
DiscordProvider({
clientId: env.DISCORD_CLIENT_ID,
clientSecret: env.DISCORD_CLIENT_SECRET,
}),
],
session: {
strategy: "jwt",
},
};

export default NextAuth(authOptions);
(it's obv not the best implementation for actually assigning roles, but finally have protected routes working with middleware and jwt.)
T
TOP2y ago
I'm still trying to get this to work, but my token is always coming back null in the callback Even when I'm logged in
c
c2y ago
if you send me a code example I can take a look
AGHA
AGHA2y ago
If ur using JWT try to delete the cookies in the browser from the application tab. refresh the page restart your app and try again. Also in next 13 your don't have ssr because your working with server components so your already on the server and writing server code. thats the default in next 13 unless your telling the module that this is a client module. (as far as i know and please correct me if i am wrong).
T
TOP2y ago
I will share some code and try deleting cookies tomorrow Sorry for the delay. Here's my middleware code
import { withAuth } from "next-auth/middleware"

export default withAuth(
// `withAuth` augments your `Request` with the user's token.
function middleware(req) {
console.log("Auth", req.nextauth.token)
},
{
callbacks: {
authorized: ({ token }) => token !== null,
},
}
)

export const config = { matcher: ["/product/:path*"] }
import { withAuth } from "next-auth/middleware"

export default withAuth(
// `withAuth` augments your `Request` with the user's token.
function middleware(req) {
console.log("Auth", req.nextauth.token)
},
{
callbacks: {
authorized: ({ token }) => token !== null,
},
}
)

export const config = { matcher: ["/product/:path*"] }
It routes to login every time I go to /product/whatever even if I already logged in Clearing cookies doesn't help
Want results from more Discord servers?
Add your server