Basic Authentication and Authorization for Password Protection
The app implements a simple authentication mechanism with an optional PASSWORD stored in the .env file. Once the user enters the password, a session cookie is created that authorizes the user for subsequent requests. The userId is a hashed version of the password, which allows all sessions to be invalidated by changing the PASSWORD env variable in production.
The authentication flow is a simplified version of the solution provided in the official Next.js authentication documentation . It implements a login page with a form that invokes a login server action . The session is created in src/lib/session.ts , and the Data Access Layer file is defined in src/lib/dal.ts .
The DAL file exports the verifySession function, which is invoked in page.tsx and redirects the user to the login page if the session is invalid.
import crypto from 'node:crypto';
import { cookies } from 'next/headers';
import { redirect } from 'next/navigation';
import { cache } from 'react';
import { decrypt } from './session';
const getSession = async () => {
const cookie = (await cookies()).get('session')?.value;
const session = await decrypt(cookie);
return session;
};
export const isLoggedIn = async () => {
if (!process.env.PASSWORD) return true;
const session = await getSession();
const userId = crypto
.createHash('md5')
.update(process.env.PASSWORD)
.digest('hex');
return session?.userId === userId;
};
export const verifySession = cache(async () => {
if (!(await isLoggedIn())) {
redirect('/login');
}
});The code above is fetched from GitHub repository.
import { verifySession } from "@/lib/dal";
export default async function Home() {
await verifySession();
// ...It also exports the isLoggedIn function, which is used by the sessionGuard decorator to check if the user is logged in when invoking procedures.
import { createDecorator, HttpException, HttpStatus } from 'vovk';
import { isLoggedIn } from '@/lib/dal';
export const sessionGuard = createDecorator(async (req, next) => {
if (typeof req.url !== 'undefined' && !(await isLoggedIn())) {
throw new HttpException(HttpStatus.UNAUTHORIZED, 'Unauthorized');
}
return next();
});The code above is fetched from GitHub repository.
The sessionGuard decorator is applied to all procedures. The typeof req.url !== 'undefined' check is required to distinguish between HTTP requests and fn invocations.