semillero-special-hotel/src/lib/auth.ts

89 lines
2.4 KiB
TypeScript

import crypto from 'crypto';
import bcrypt from 'bcryptjs';
import { NextRequest } from 'next/server';
if (!process.env.NEXTAUTH_SECRET) {
throw new Error('FATAL: NEXTAUTH_SECRET environment variable is missing.');
}
const JWT_SECRET = process.env.NEXTAUTH_SECRET;
export interface UserSession {
userId: number;
username: string;
email: string;
role: string;
hotelId: number;
regionId: number;
}
// Base64URL encoding helpers
function base64urlEncode(str: string): string {
return Buffer.from(str).toString('base64url');
}
function base64urlDecode(str: string): string {
return Buffer.from(str, 'base64url').toString('utf8');
}
// Sign JWT natively
export function signJwt(payload: object, expiresInSeconds = 86400): string {
const header = { alg: 'HS256', typ: 'JWT' };
const exp = Math.floor(Date.now() / 1000) + expiresInSeconds;
const fullPayload = { ...payload, exp };
const encodedHeader = base64urlEncode(JSON.stringify(header));
const encodedPayload = base64urlEncode(JSON.stringify(fullPayload));
const signature = crypto
.createHmac('sha256', JWT_SECRET)
.update(`${encodedHeader}.${encodedPayload}`)
.digest('base64url');
return `${encodedHeader}.${encodedPayload}.${signature}`;
}
// Verify JWT natively
export function verifyJwt(token: string): UserSession | null {
try {
const parts = token.split('.');
if (parts.length !== 3) return null;
const [headerB64, payloadB64, signature] = parts;
const expectedSignature = crypto
.createHmac('sha256', JWT_SECRET)
.update(`${headerB64}.${payloadB64}`)
.digest('base64url');
if (signature !== expectedSignature) return null;
const payload = JSON.parse(base64urlDecode(payloadB64));
// Check expiration
if (payload.exp && Date.now() / 1000 > payload.exp) {
return null;
}
return payload as UserSession;
} catch (err) {
return null;
}
}
// Compare password hash
export async function comparePassword(password: string, hash: string): Promise<boolean> {
return bcrypt.compare(password, hash);
}
// Hash password
export async function hashPassword(password: string): Promise<string> {
return bcrypt.hash(password, 10);
}
// Get session from request cookies
export function getSession(req: NextRequest): UserSession | null {
const cookie = req.cookies.get('session');
if (!cookie?.value) return null;
return verifyJwt(cookie.value);
}