Skip to content

Commit

Permalink
added routes for mobile login and changed middleware for authorization
Browse files Browse the repository at this point in the history
  • Loading branch information
nimit9 committed Jun 6, 2024
1 parent 0be2f33 commit 7848d89
Show file tree
Hide file tree
Showing 7 changed files with 242 additions and 118 deletions.
27 changes: 27 additions & 0 deletions src/app/api/auth/mobile/login/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { NextRequest, NextResponse } from 'next/server';
import { authorize } from '@/lib/auth';

export async function POST(request: NextRequest) {
try {
const reqBody = await request.json();
const { username, password } = reqBody;

const user = await authorize({ username, password });

if (!user) {
return NextResponse.json(
{ error: 'User does not exist' },
{ status: 400 },
);
}
const { token, ...otherProperties } = user;
const response = NextResponse.json({
message: 'Login successful',
token,
user: { ...otherProperties },
});
return response;
} catch (error: any) {
return NextResponse.json({ error: error.message }, { status: 500 });
}
}
28 changes: 28 additions & 0 deletions src/app/api/auth/mobile/logout/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { NextRequest, NextResponse } from 'next/server';
import db from '@/db';

export async function POST(request: NextRequest) {
try {
const body = await request.json();
if (body && body.userId) {
await db.user.update({
where: {
id: body.userId,
},
data: {
token: null,
},
});
return NextResponse.json({
message: 'Logout successful',
success: true,
});
}
return NextResponse.json(
{ message: 'User Id not available' },
{ status: 400 },
);
} catch (error: any) {
return NextResponse.json({ error: error.message }, { status: 500 });
}
}
Empty file removed src/app/data/index.ts
Empty file.
6 changes: 3 additions & 3 deletions src/components/BreadCrumbComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
} from '@/components/ui/breadcrumb';
import { FullCourseContent } from '@/db/course';
import Link from 'next/link';
import { useMemo } from 'react';
import { Fragment, useMemo } from 'react';

export default function BreadCrumbComponent({
rest,
Expand Down Expand Up @@ -89,7 +89,7 @@ export default function BreadCrumbComponent({
finalRouteArray = [...rest];
}
return (
<>
<Fragment key={breadcrumb.id}>
{index !== array.length - 1 ? (
<>
<BreadcrumbItem>
Expand All @@ -111,7 +111,7 @@ export default function BreadCrumbComponent({
</BreadcrumbPage>
</BreadcrumbItem>
)}
</>
</Fragment>
);
})}
</BreadcrumbList>
Expand Down
204 changes: 106 additions & 98 deletions src/lib/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ const generateJWT = async (payload: JWTPayload) => {

return jwt;
};

async function validateUser(
email: string,
password: string,
Expand Down Expand Up @@ -106,6 +107,110 @@ async function validateUser(
};
}

export const authorize = async (credentials?: {
username: string;
password: string;
}) => {
if (!credentials?.username || !credentials?.password) {
return null;
}
try {
if (process.env.LOCAL_CMS_PROVIDER) {
return {
id: '1',
name: 'test',
email: '[email protected]',
token: await generateJWT({
id: '1',
}),
};
}
const hashedPassword = await bcrypt.hash(credentials.password, 10);

const userDb = await prisma.user.findFirst({
where: {
email: credentials.username,
},
select: {
password: true,
id: true,
name: true,
},
});
if (
userDb &&
userDb.password &&
(await bcrypt.compare(credentials.password, userDb.password))
) {
const jwt = await generateJWT({
id: userDb.id,
});
await db.user.update({
where: {
id: userDb.id,
},
data: {
token: jwt,
},
});

return {
id: userDb.id,
name: userDb.name,
email: credentials.username,
token: jwt,
};
}
const user: AppxSigninResponse = await validateUser(
credentials.username,
credentials.password,
);

const jwt = await generateJWT({
id: user.data?.userid,
});

if (user.data) {
try {
await db.user.upsert({
where: {
id: user.data.userid,
},
create: {
id: user.data.userid,
name: user.data.name,
email: credentials.username,
token: jwt,
password: hashedPassword,
},
update: {
id: user.data.userid,
name: user.data.name,
email: credentials.username,
token: jwt,
password: hashedPassword,
},
});
} catch (e) {
console.log(e);
}

return {
id: user.data.userid,
name: user.data.name,
email: credentials.username,
token: jwt,
};
}

// Return null if user data could not be retrieved
return null;
} catch (e) {
console.error(e);
}
return null;
};

export const authOptions = {
providers: [
CredentialsProvider({
Expand All @@ -114,104 +219,7 @@ export const authOptions = {
username: { label: 'email', type: 'text', placeholder: '' },
password: { label: 'password', type: 'password', placeholder: '' },
},
async authorize(credentials: any) {
try {
if (process.env.LOCAL_CMS_PROVIDER) {
return {
id: '1',
name: 'test',
email: '[email protected]',
token: await generateJWT({
id: '1',
}),
};
}
const hashedPassword = await bcrypt.hash(credentials.password, 10);

const userDb = await prisma.user.findFirst({
where: {
email: credentials.username,
},
select: {
password: true,
id: true,
name: true,
},
});
if (
userDb &&
userDb.password &&
(await bcrypt.compare(credentials.password, userDb.password))
) {
const jwt = await generateJWT({
id: userDb.id,
});
await db.user.update({
where: {
id: userDb.id,
},
data: {
token: jwt,
},
});

return {
id: userDb.id,
name: userDb.name,
email: credentials.username,
token: jwt,
};
}
console.log('not in db');
const user: AppxSigninResponse = await validateUser(
credentials.username,
credentials.password,
);

const jwt = await generateJWT({
id: user.data?.userid,
});

if (user.data) {
try {
await db.user.upsert({
where: {
id: user.data.userid,
},
create: {
id: user.data.userid,
name: user.data.name,
email: credentials.username,
token: jwt,
password: hashedPassword,
},
update: {
id: user.data.userid,
name: user.data.name,
email: credentials.username,
token: jwt,
password: hashedPassword,
},
});
} catch (e) {
console.log(e);
}

return {
id: user.data.userid,
name: user.data.name,
email: credentials.username,
token: jwt,
};
}

// Return null if user data could not be retrieved
return null;
} catch (e) {
console.error(e);
}
return null;
},
authorize,
}),
],
secret: process.env.NEXTAUTH_SECRET || 'secr3t',
Expand Down
54 changes: 54 additions & 0 deletions src/lib/middleware-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { importJWK, jwtVerify } from 'jose';
import { NextRequestWithAuth, withAuth } from 'next-auth/middleware';
import { NextResponse } from 'next/server';

const PRIVATE_MOBILE_ROUTES = ['/api/auth/mobile/logout'];
const SINGLE_USER_ROUTES = ['/courses', '/questions', '/bookmarks'];

const shouldRestrictSingleUser = (pathname: string) => {
return SINGLE_USER_ROUTES.some((route) => pathname.startsWith(route));
};

const verifyJWT = async (token: string) => {
const secret = process.env.JWT_SECRET || 'secret';
const jwk = await importJWK({ k: secret, alg: 'HS256', kty: 'oct' });
const payload = await jwtVerify(token, jwk);
return payload;
};

export const handleMobileAuth = async (request: NextRequestWithAuth) => {
const token = request.headers.get('Authorization')?.split(' ')[1];
const pathname = request.nextUrl.pathname;
if (token) {
try {
const payload: any = await verifyJWT(token);
request.nextUrl.searchParams.set('userId', payload.id);
return NextResponse.next();
} catch (error) {
return NextResponse.json({ message: 'Unauthorized' }, { status: 401 });
}
} else if (PRIVATE_MOBILE_ROUTES.includes(pathname)) {
return NextResponse.json({ message: 'Unauthorized' }, { status: 401 });
}
};

export const nextAuthMiddleware = withAuth(async (req) => {
if (process.env.LOCAL_CMS_PROVIDER) return;

const pathname = req.nextUrl.pathname;

if (shouldRestrictSingleUser(pathname)) {
const token = req.nextauth.token;
if (!token) {
return NextResponse.redirect(new URL('/invalidsession', req.url));
}
const user = await fetch(
`${process.env.NEXT_PUBLIC_BASE_URL_LOCAL}/api/user?token=${token.jwtToken}`,
);

const json = await user.json();
if (!json.user) {
return NextResponse.redirect(new URL('/invalidsession', req.url));
}
}
});
Loading

0 comments on commit 7848d89

Please sign in to comment.