Skip to content

Instantly share code, notes, and snippets.

@carlohcs
Created March 20, 2022 15:31
Show Gist options
  • Save carlohcs/374581de281ac9d52abfdba0fe13ae54 to your computer and use it in GitHub Desktop.
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 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 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 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 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