├── .eslintrc.json ├── .gitignore ├── README.md ├── app ├── api │ ├── auth │ │ ├── login │ │ │ └── route.js │ │ └── logout │ │ │ └── route.js │ ├── hello │ │ └── route.js │ └── profile │ │ └── route.js ├── dashboard │ └── page.jsx ├── globals.css ├── layout.jsx ├── login │ └── page.jsx └── page.jsx ├── middleware.js ├── next.config.js ├── package-lock.json ├── package.json └── public ├── favicon.ico └── vercel.svg /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | .pnpm-debug.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | ``` 12 | 13 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 14 | 15 | You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file. 16 | 17 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`. 18 | 19 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. 20 | 21 | ## Learn More 22 | 23 | To learn more about Next.js, take a look at the following resources: 24 | 25 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 26 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 27 | 28 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 29 | 30 | ## Deploy on Vercel 31 | 32 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 33 | 34 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 35 | -------------------------------------------------------------------------------- /app/api/auth/login/route.js: -------------------------------------------------------------------------------- 1 | import { sign } from "jsonwebtoken"; 2 | import { NextResponse } from "next/server"; 3 | 4 | export async function POST(request) { 5 | const { email, password } = await request.json(); 6 | 7 | if (email === "admin@local.local" && password === "admin") { 8 | // expire in 30 days 9 | const token = sign( 10 | { 11 | exp: Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 30, 12 | email, 13 | username: "fazt", 14 | }, 15 | "secret" 16 | ); 17 | 18 | const response = NextResponse.json({ 19 | token, 20 | }); 21 | 22 | response.cookies.set({ 23 | name: "myTokenName", 24 | value: token, 25 | httpOnly: true, 26 | secure: process.env.NODE_ENV === "production", 27 | sameSite: "strict", 28 | maxAge: 1000 * 60 * 60 * 24 * 30, 29 | path: "/", 30 | }); 31 | 32 | return response; 33 | } else { 34 | return NextResponse.json( 35 | { 36 | message: "Invalid credentials", 37 | }, 38 | { 39 | status: 401, 40 | } 41 | ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/api/auth/logout/route.js: -------------------------------------------------------------------------------- 1 | import { NextResponse } from "next/server"; 2 | import { cookies } from "next/headers"; 3 | 4 | export function GET(request) { 5 | const cookieStore = cookies(); 6 | const token = cookieStore.get("myTokenName"); 7 | console.log(token); 8 | 9 | if (!token) { 10 | return NextResponse.json({ 11 | message: "Not logged in", 12 | }, { 13 | status: 401, 14 | }) 15 | } 16 | 17 | try { 18 | cookieStore.delete("myTokenName"); 19 | 20 | const response = NextResponse.json( 21 | {}, 22 | { 23 | status: 200, 24 | } 25 | ); 26 | 27 | return response; 28 | } catch (error) { 29 | console.log(error); 30 | return NextResponse.json(error.message, { 31 | status: 500, 32 | }); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/api/hello/route.js: -------------------------------------------------------------------------------- 1 | import { NextResponse } from "next/server"; 2 | 3 | export function GET(request) { 4 | return NextResponse.json({ 5 | message: "Hello World", 6 | }); 7 | } 8 | -------------------------------------------------------------------------------- /app/api/profile/route.js: -------------------------------------------------------------------------------- 1 | import jwt from "jsonwebtoken"; 2 | import { cookies } from "next/headers"; 3 | import { NextResponse } from "next/server"; 4 | 5 | export function GET(request) { 6 | const cookieStore = cookies(); 7 | const token = cookieStore.get("myTokenName"); 8 | 9 | if (!token) { 10 | return res.status(401).json({ error: "Not logged in" }); 11 | } 12 | 13 | const {email, username} = jwt.verify(token.value, "secret"); 14 | 15 | return NextResponse.json({ 16 | email, 17 | username, 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /app/dashboard/page.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import axios from "axios"; 4 | import { useState } from "react"; 5 | import { useRouter } from "next/navigation"; 6 | 7 | function Dashboard() { 8 | const [user, setUser] = useState({ 9 | email: "", 10 | username: "", 11 | }); 12 | const router = useRouter(); 13 | 14 | const getProfile = async () => { 15 | const profile = await axios.get("/api/profile"); 16 | setUser(profile.data); 17 | }; 18 | 19 | const logout = async () => { 20 | try { 21 | const res = await axios.get("/api/auth/logout"); 22 | console.log(res); 23 | } catch (error) { 24 | console.error(error.message); 25 | } 26 | router.push("/login"); 27 | }; 28 | return ( 29 |