├── .eslintignore ├── public ├── favicon.ico ├── vercel.svg ├── jwt.svg └── nextjs.svg ├── .prettierrc.js ├── pages ├── api │ ├── hello.js │ ├── about.js │ └── auth.js ├── about.js └── index.js ├── .gitignore ├── components ├── navigation │ └── User.jsx ├── header │ └── Header.jsx ├── footer │ └── Footer.jsx ├── form │ ├── FormLogin.jsx │ ├── FormPost.jsx │ ├── FormRegister.jsx │ └── FormJob.jsx └── layout │ └── Layout.jsx ├── package.json ├── README.md ├── .eslintrc.js ├── middleware └── utils.js ├── auth.drawio └── schemas.drawio /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/* -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dyarfi/nextjs-jwt/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | tabWidth: 2, 3 | singleQuote: true, 4 | trailingComma: 'all', 5 | }; 6 | -------------------------------------------------------------------------------- /pages/api/hello.js: -------------------------------------------------------------------------------- 1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction 2 | export default (req, res) => { 3 | res.statusCode = 200; 4 | res.json({ name: 'John Doe' }); 5 | }; 6 | -------------------------------------------------------------------------------- /.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 | 21 | # debug 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | 26 | # local env files 27 | .env.local 28 | .env.development.local 29 | .env.test.local 30 | .env.production.local 31 | 32 | .vercel 33 | -------------------------------------------------------------------------------- /pages/api/about.js: -------------------------------------------------------------------------------- 1 | const CODE = 200; 2 | 3 | export default (req, res) => { 4 | return new Promise(resolve => { 5 | const { method } = req; 6 | let message = {}; 7 | try { 8 | switch (method) { 9 | case 'POST': 10 | /* Post method */ 11 | break; 12 | case 'PUT': 13 | /* Put method */ 14 | break; 15 | case 'PATCH': 16 | /* Patch method */ 17 | break; 18 | /* Get */ 19 | default: 20 | break; 21 | } 22 | res.statusCode = CODE; 23 | res.json({ message }); 24 | } catch (error) { 25 | throw error; 26 | } 27 | res.status(405).end(); 28 | return resolve(); 29 | }); 30 | }; 31 | -------------------------------------------------------------------------------- /components/navigation/User.jsx: -------------------------------------------------------------------------------- 1 | import Link from 'next/link'; 2 | 3 | /* Components */ 4 | // import DarkModeToggle from "../DarkModeToggle"; 5 | 6 | const User = ({ props }) => { 7 | const { user } = props; 8 | 9 | return ( 10 |

11 | {(user && ( 12 | 13 | Logout 14 | 15 | )) || ( 16 | <> 17 | Have an Account? 18 | 19 | Login 20 | 21 | or 22 | 23 | Register 24 | 25 | 26 | )} 27 |

28 | ); 29 | }; 30 | 31 | export default User; 32 | -------------------------------------------------------------------------------- /components/header/Header.jsx: -------------------------------------------------------------------------------- 1 | import Link from 'next/link'; 2 | 3 | /* Components */ 4 | // import DarkModeToggle from "../DarkModeToggle"; 5 | 6 | const Header = ({ props }) => { 7 | return ( 8 | <> 9 | 26 | 31 | 32 | ); 33 | }; 34 | 35 | export default Header; 36 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nextjs-jwt", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start" 9 | }, 10 | "dependencies": { 11 | "bcryptjs": "^2.4.3", 12 | "js-cookie": "^2.2.1", 13 | "jsonwebtoken": "^8.5.1", 14 | "next": "^9.5.3", 15 | "react": "16.13.1", 16 | "react-dom": "16.13.1" 17 | }, 18 | "devDependencies": { 19 | "@babel/core": "^7.5.5", 20 | "@babel/plugin-proposal-class-properties": "^7.5.5", 21 | "@babel/plugin-syntax-dynamic-import": "^7.2.0", 22 | "@babel/polyfill": "^7.4.4", 23 | "@babel/preset-env": "^7.5.5", 24 | "@babel/preset-react": "^7.0.0", 25 | "babel-eslint": "^10.0.2", 26 | "eslint": "^6.1.0", 27 | "eslint-config-airbnb": "^17.1.1", 28 | "eslint-config-prettier": "^6.0.0", 29 | "eslint-plugin-import": "^2.18.0", 30 | "eslint-plugin-jsx-a11y": "^6.2.3", 31 | "eslint-plugin-prettier": "^3.1.0", 32 | "eslint-plugin-react": "^7.14.2", 33 | "prettier": "^1.18.2" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /public/jwt.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /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 | ## Learn More 18 | 19 | To learn more about Next.js, take a look at the following resources: 20 | 21 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 22 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 23 | 24 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 25 | 26 | ## Deploy on Vercel 27 | 28 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/import?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 29 | 30 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 31 | -------------------------------------------------------------------------------- /components/footer/Footer.jsx: -------------------------------------------------------------------------------- 1 | export default function Footer({ copyright = '2020' }) { 2 | return ( 3 | 38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /public/nextjs.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | es6: true, 5 | node: true, 6 | }, 7 | extends: ['airbnb', 'prettier', 'prettier/react'], 8 | globals: { 9 | Atomics: 'readonly', 10 | SharedArrayBuffer: 'readonly', 11 | }, 12 | parser: 'babel-eslint', 13 | parserOptions: { 14 | ecmaFeatures: { 15 | jsx: true, 16 | }, 17 | ecmaVersion: 2018, 18 | sourceType: 'module', 19 | allowImportExportEverywhere: true, 20 | }, 21 | plugins: ['react', 'prettier'], 22 | rules: { 23 | 'prettier/prettier': 'error', 24 | 'no-console': 0, 25 | 'no-nested-ternary': 0, 26 | 'import/order': 0, 27 | 'import/no-extraneous-dependencies': 0, 28 | 'jsx-a11y/anchor-is-valid': 0, 29 | 'react/no-array-index-key': 0, 30 | 'react/prefer-stateless-function': 0, 31 | 'react/sort-comp': 0, 32 | 'no-plusplus': ['error', { allowForLoopAfterthoughts: true }], 33 | 'no-use-before-define': [ 34 | 'error', 35 | { functions: false, classes: false, variables: false }, 36 | ], 37 | 'react/jsx-filename-extension': [ 38 | 1, 39 | { 40 | extensions: ['.js', 'jsx'], 41 | }, 42 | ], 43 | 'react/forbid-prop-types': 0, 44 | 'react/prop-types': 0, 45 | /* 'react/prop-types': [ 46 | 'enabled', 47 | { ignore: 'ignore', customValidators: 'customValidator' }, 48 | ], */ 49 | // 'max-len': ['error', 80], 50 | }, 51 | settings: { 52 | 'import/resolver': { 53 | node: { 54 | extensions: ['.js', '.jsx', '.ts', '.tsx'], 55 | }, 56 | }, 57 | }, 58 | }; 59 | -------------------------------------------------------------------------------- /components/form/FormLogin.jsx: -------------------------------------------------------------------------------- 1 | function FormLogin({ props }) { 2 | const { 3 | onSubmitHandler, 4 | onChangeHandler, 5 | stateFormData, 6 | stateFormError, 7 | stateFormMessage, 8 | } = props; 9 | return ( 10 |
11 |
12 |

Login

13 |
14 | {stateFormMessage.status === "error" && ( 15 |

{stateFormMessage.error}

16 | )} 17 |
18 |
19 | 20 | 29 | {stateFormError.email && ( 30 | {stateFormError.email.hint} 31 | )} 32 |
33 |
34 | 35 | 44 | {stateFormError.password && ( 45 | {stateFormError.password.hint} 46 | )} 47 |
48 |
49 | 52 |
53 |
54 | ); 55 | } 56 | export default FormLogin; 57 | -------------------------------------------------------------------------------- /components/form/FormPost.jsx: -------------------------------------------------------------------------------- 1 | function FormPost(props) { 2 | const { 3 | onSubmit, 4 | onChange, 5 | stateFormData, 6 | stateFormError, 7 | stateFormValid, 8 | stateFormMessage, 9 | } = props; 10 | return ( 11 |
12 |
13 |

Form Post

14 |
15 | {stateFormMessage.status === 'error' && ( 16 |

{stateFormMessage.error}

17 | )} 18 |
19 |
20 | 21 | 31 | {stateFormError.title && ( 32 | {stateFormError.title.hint} 33 | )} 34 |
35 |
36 | 37 |