Created
March 20, 2022 15:31
-
-
Save carlohcs/374581de281ac9d52abfdba0fe13ae54 to your computer and use it in GitHub Desktop.
Next.js middleware to check if user could access a private route
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This file should be placed at pages/_middleware.ts | |
import { NextRequest, NextResponse } from 'next/server' | |
import { verifyIsLogged } from 'services/session' | |
const BASE_URL = 'https://my-site.com' | |
const PRIVATE_ROUTES = ['my-profile'] | |
const LOGIN_URL = `${BASE_URL}/api/auth?redir=` | |
export async function middleware(req: NextRequest) { | |
const currentRoute = req.page.name | |
// Check if the user is trying to access a protected route | |
// If so, check if he is logged in to access the page. If not, send him to the login url | |
if (PRIVATE_ROUTES.indexOf(`${currentRoute?.replace('/', '')}`) > -1) { | |
const isLogged = await verifyIsLogged(req) | |
if (!isLogged) { | |
// Redirect to 'https://my-site.com/api/auth?redir=https://my-site.com/my-profile' | |
const loginUrl = `${LOGIN_URL}${BASE_URL}${currentRoute}` | |
return NextResponse.redirect(loginUrl) | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This file should be placed at pages/pages/my-profile.tsx | |
export default function MyProfile(props: any) { | |
return ( | |
<div> | |
<h1>My Profile</h1> | |
<div> | |
<p>You are only seeing this page because you are logged in.</p> | |
</div> | |
</div> | |
) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This file should be placed at pages/api/session.ts | |
import type { NextApiRequest, NextApiResponse } from 'next' | |
const validateCookiesInOurDBOrSomethingElse = (cookies: []) => ...logic here... | |
export default (req: NextApiRequest, res: NextApiResponse) => { | |
const { method } = req | |
switch (method) { | |
case 'GET': | |
// Here you define your logic to check if user is logged. | |
// Above, just an example based on cookies | |
const {COOKIE_A, COOKIE_B} = req.cookies | |
if ( validateCookiesInOurDBOrSomethingElse( [ COOKIE_A, COOKIE_B ] ) { | |
res.status(200).json({ message: 'User is logged.' }) | |
} | |
res.status(401).json({ message: 'User isn't logged.' }) | |
break | |
default: | |
} | |
res.status(405).json({ error: `Method ${method} Not Allowed` }) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This file should be placed at services/session.ts | |
// This file is just an example, you need to define a logic to check if user is logged | |
import { NextRequest } from 'next/server' | |
import axios from 'axios' | |
const parseSiteDefaultCookies = (cookie: string, name: string) => { | |
let find = cookie.split(';').find((item) => { | |
return item.split('=')[0].trim().toUpperCase() === name.toUpperCase() | |
}) | |
return find?.split(`${name}=`)[1].trim() | |
} | |
export const verifyIsLogged = async (req?: NextRequest) => { | |
let headers: any = {} | |
try { | |
if (req) { | |
const userAgent = req.headers.get('user-agent') | |
const cookie = req.headers.get('cookie') | |
headers.UserAgent = userAgent | |
if (cookie) { | |
const COOKIE_A = parseSiteDefaultCookies(cookie, 'COOKIE_A') | |
const COOKIE_B = parseSiteDefaultCookies(cookie, 'COOKIE_B') | |
headers.Cookie = `COOKIE_A=${COOKIE_A}; COOKIE_B=${COOKIE_B}` | |
} | |
} | |
} catch (error: any) { | |
console.log('Error to parse cookies: ', error.message) | |
} | |
try { | |
const response = await axios.head('/api/session', { headers }) | |
return [200, 201, 204].indexOf(response.status) !== -1 | |
} catch (error: any) { | |
console.log('Error to HEAD session: ', error?.message) | |
return false | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment