Feat: Add complete auth system (Login, Register, OTP/2FA via Telegram, Session management)
This commit is contained in:
@@ -1,34 +1,77 @@
|
||||
import { NextResponse } from 'next/server'
|
||||
import type { NextRequest } from 'next/server'
|
||||
import { NextResponse } from 'next/server';
|
||||
import type { NextRequest } from 'next/server';
|
||||
import { jwtVerify } from 'jose';
|
||||
|
||||
export function middleware(request: NextRequest) {
|
||||
const token = request.cookies.get('auth_token')
|
||||
|
||||
// Public paths that don't require authentication
|
||||
const SECRET_KEY = new TextEncoder().encode(process.env.JWT_SECRET || 'fallback-secret-key-change-me');
|
||||
|
||||
export async function middleware(request: NextRequest) {
|
||||
const session = request.cookies.get('session')?.value;
|
||||
const { pathname } = request.nextUrl;
|
||||
|
||||
// Paths that are always public
|
||||
const publicPaths = [
|
||||
'/login',
|
||||
'/register',
|
||||
'/api/auth/login',
|
||||
'/api/auth/register',
|
||||
'/api/auth/verify-otp',
|
||||
'/api/auth/send'
|
||||
];
|
||||
|
||||
// Static assets and Next.js internals
|
||||
if (
|
||||
request.nextUrl.pathname.startsWith('/_next') ||
|
||||
request.nextUrl.pathname.startsWith('/static') ||
|
||||
request.nextUrl.pathname === '/login' ||
|
||||
request.nextUrl.pathname === '/favicon.ico' ||
|
||||
request.nextUrl.pathname.startsWith('/api/auth')
|
||||
pathname.startsWith('/_next') ||
|
||||
pathname.startsWith('/static') ||
|
||||
pathname.includes('.') // images, icons, etc
|
||||
) {
|
||||
// If user is already logged in and tries to access login, redirect to dashboard
|
||||
if (token && request.nextUrl.pathname === '/login') {
|
||||
return NextResponse.redirect(new URL('/', request.url))
|
||||
return NextResponse.next();
|
||||
}
|
||||
|
||||
const isPublic = publicPaths.some(path => pathname.startsWith(path));
|
||||
|
||||
// If user has session, try to verify it
|
||||
let isValidSession = false;
|
||||
if (session) {
|
||||
try {
|
||||
await jwtVerify(session, SECRET_KEY);
|
||||
isValidSession = true;
|
||||
} catch (e) {
|
||||
isValidSession = false;
|
||||
}
|
||||
return NextResponse.next()
|
||||
}
|
||||
|
||||
// If no token, redirect to login
|
||||
if (!token) {
|
||||
return NextResponse.redirect(new URL('/login', request.url))
|
||||
// Logic:
|
||||
|
||||
// 1. If public path and Logged In -> Redirect to Dashboard
|
||||
if (isPublic && isValidSession && (pathname === '/login' || pathname === '/register')) {
|
||||
return NextResponse.redirect(new URL('/', request.url));
|
||||
}
|
||||
|
||||
return NextResponse.next()
|
||||
// 2. If public path -> Allow
|
||||
if (isPublic) {
|
||||
return NextResponse.next();
|
||||
}
|
||||
|
||||
// 3. If protected path and Not Logged In -> Redirect to Login
|
||||
if (!isValidSession) {
|
||||
const loginUrl = new URL('/login', request.url);
|
||||
// Optional: Add ?from=pathname to redirect back after login
|
||||
return NextResponse.redirect(loginUrl);
|
||||
}
|
||||
|
||||
// 4. Protected path and Logged In -> Allow
|
||||
return NextResponse.next();
|
||||
}
|
||||
|
||||
export const config = {
|
||||
matcher: [
|
||||
/*
|
||||
* Match all request paths except for the ones starting with:
|
||||
* - api (API routes) -> Wait, we WANT to protect API routes except auth ones
|
||||
* - _next/static (static files)
|
||||
* - _next/image (image optimization files)
|
||||
* - favicon.ico (favicon file)
|
||||
*/
|
||||
'/((?!_next/static|_next/image|favicon.ico).*)',
|
||||
],
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user