├── config.ts ├── .eslintrc.json ├── .github ├── FUNDING.yml └── ISSUE_TEMPLATE │ └── feature_request.md ├── public ├── favicon.ico └── replit.svg ├── postcss.config.js ├── next.config.js ├── replit.nix ├── next-env.d.ts ├── pages ├── _app.tsx ├── api │ ├── hello.ts │ └── _auth │ │ └── user.js ├── _auth │ └── [_code].js └── index.js ├── tailwind.config.js ├── styles └── globals.css ├── .gitignore ├── backend ├── package.json └── index.js ├── tsconfig.json ├── README.md ├── package.json └── .replit /config.ts: -------------------------------------------------------------------------------- 1 | export const API_HOST = "api url" -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: kardespro 4 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kardespro/nextjs-discord-auth/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | } 5 | 6 | module.exports = nextConfig 7 | -------------------------------------------------------------------------------- /replit.nix: -------------------------------------------------------------------------------- 1 | { pkgs }: { 2 | deps = [ 3 | pkgs.nodejs-16_x 4 | pkgs.nodePackages.typescript-language-server 5 | pkgs.nodePackages.yarn 6 | pkgs.replitPackages.jest 7 | ]; 8 | } -------------------------------------------------------------------------------- /next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import '../styles/globals.css' 2 | import type { AppProps } from 'next/app' 3 | 4 | function MyApp({ Component, pageProps }: AppProps) { 5 | return 6 | } 7 | 8 | export default MyApp 9 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | "./app/**/*.{js,ts,jsx,tsx}", 5 | "./pages/**/*.{js,ts,jsx,tsx}", 6 | "./components/**/*.{js,ts,jsx,tsx}", 7 | ], 8 | theme: { 9 | extend: {}, 10 | }, 11 | plugins: [], 12 | } -------------------------------------------------------------------------------- /styles/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | body { 6 | 7 | @apply flex flex-col items-center justify-center text-gray-800; 8 | 9 | background: #f3f4f6; 10 | 11 | } 12 | 13 | 14 | #__layout { 15 | @apply h-full w-full; 16 | } 17 | .r{ 18 | border-radius:50%; 19 | } -------------------------------------------------------------------------------- /pages/api/hello.ts: -------------------------------------------------------------------------------- 1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction 2 | import type { NextApiRequest, NextApiResponse } from 'next' 3 | 4 | type Data = { 5 | name: string 6 | } 7 | 8 | export default function handler( 9 | req: NextApiRequest, 10 | res: NextApiResponse 11 | ) { 12 | res.status(200).json({ name: 'John Doe' }) 13 | } 14 | -------------------------------------------------------------------------------- /.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 | 34 | # typescript 35 | *.tsbuildinfo 36 | -------------------------------------------------------------------------------- /backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodejs", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "@types/node": "^18.0.6", 14 | "body-parser": "^1.20.2", 15 | "cors": "^2.8.5", 16 | "express": "^4.18.2", 17 | "express-session": "^1.17.3", 18 | "node-fetch": "^3.2.6", 19 | "passport": "^0.6.0", 20 | "passport-discord": "^0.1.4" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true 17 | }, 18 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 19 | "exclude": ["node_modules"] 20 | } 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Next.js Discord Auth 2 | 3 | **Start Downloading Project** 4 | 5 | ```bash 6 | git clone https://github.com/kardespro/nextjs-discord-auth 7 | cd nextjs-discord-auth 8 | ``` 9 | 10 | **Download Modules** 11 | 12 | ```bash 13 | npm i -y 14 | ``` 15 | 16 | **Configure** 17 | 18 | ```js 19 | //config.ts 20 | 21 | export const API_HOST = "api url" 22 | 23 | ``` 24 | 25 | **Start Frontend Server** 26 | 27 | ```bash 28 | npm run nego 29 | ``` 30 | 31 | **Deploy Backend Server** 32 | 33 | ```bash 34 | cd backend 35 | ``` 36 | 37 | **Download Modules** 38 | 39 | ```bash 40 | npm i 41 | ``` 42 | 43 | **Fill Sections in index.js** 44 | 45 | **Start Server** 46 | 47 | ```bash 48 | node . 49 | ##or 50 | node index.js 51 | ``` 52 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-app", 3 | "description": "Discord Auth With Next.js", 4 | "version": "0.1.0", 5 | "private": true, 6 | "scripts": { 7 | "dev": "next dev", 8 | "build": "next build", 9 | "start": "next start", 10 | "lint": "next lint", 11 | "nego": "next build && next start" 12 | }, 13 | "dependencies": { 14 | "axios": "^1.3.5", 15 | "next": "12.2.0", 16 | "react": "18.2.0", 17 | "react-dom": "18.2.0" 18 | }, 19 | "devDependencies": { 20 | "@types/node": "18.0.1", 21 | "@types/react": "18.0.14", 22 | "@types/react-dom": "18.0.5", 23 | "autoprefixer": "^10.4.13", 24 | "eslint": "8.19.0", 25 | "eslint-config-next": "12.2.0", 26 | "postcss": "^8.4.19", 27 | "tailwindcss": "^3.2.4", 28 | "typescript": "4.7.4" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /pages/_auth/[_code].js: -------------------------------------------------------------------------------- 1 | import { useRouter } from 'next/router' 2 | import { useEffect, useState } from 'react' 3 | import axios from 'axios' 4 | export default function _Auth(){ 5 | const router = useRouter() 6 | const { _code } = router.query 7 | const [error,setError] = useState("") 8 | useEffect(() => { 9 | (async() => { 10 | if(_code) { 11 | let _loadUser = await axios.get(`/api/_auth/user?token=${_code}`) 12 | if(_loadUser.data.status === 401){ 13 | setError("Token Incorrect") 14 | } 15 | if(_loadUser.data.status === 200){ 16 | window.localStorage.setItem("__nego-auth", _code) 17 | router.push("/") 18 | } 19 | } 20 | })() 21 | }) 22 | return( 23 | <> 24 |
25 | {error && 26 |
27 |

{error}

28 |
29 | } 30 | 31 | ) 32 | } -------------------------------------------------------------------------------- /pages/api/_auth/user.js: -------------------------------------------------------------------------------- 1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction 2 | 3 | import axios from 'axios' 4 | 5 | export default async function handler( 6 | req,res 7 | ) { 8 | if(req.method !== "GET") return res.json({ status: 405, message: "405. Method Not Allowed", id: "", username:"", avatarURL: "", discriminator: "", avatar: ""}) 9 | let _userReq = req.query 10 | if(!_userReq.token) return res.status(200).json({ status: 404, message: "404",id: "", username:"", avatarURL: "", discriminator: "", avatar: ""}) 11 | let data = await axios.get("https://discord.com/api/v9/users/@me", { headers: { "Authorization": `Bearer ${_userReq.token}`}}).catch(err => res.status(200).json({ status: 401, message: "401", id: "", username:"", avatarURL: "", discriminator: "", avatar: ""})) 12 | if(data.status === 401) return res.json({ status: 401, message: "401. Token Incorrect"}) 13 | res.status(200).json({ 14 | status: 200, 15 | message: "200, Token Correct", 16 | id: data.data.id, 17 | username: data.data.username, 18 | discriminator: data.data.discriminator, 19 | avatarURL: `https://cdn.discordapp.com/avatars/${data.data.id}/${data.data.avatar}`, 20 | avatar: data.data.avatar 21 | }) 22 | 23 | } 24 | -------------------------------------------------------------------------------- /public/replit.svg: -------------------------------------------------------------------------------- 1 | replit logo -------------------------------------------------------------------------------- /backend/index.js: -------------------------------------------------------------------------------- 1 | const Strategy = require("passport-discord").Strategy; 2 | const express = require('express') 3 | const app = express() 4 | const passport = require('passport'); 5 | const session = require('express-session'); 6 | 7 | let domain = `frontendurl` 8 | 9 | app.use( 10 | session({ 11 | secret: "55CWSa21QbGeNxiJX3HngI7gm_F5bEGiZMGDu5rcUlDqILu1K9q_m4wDHDX3Prk84xurn9gyZgVIr", 12 | resave: false, 13 | saveUninitialized: false 14 | }) 15 | ); 16 | 17 | app.use(require('body-parser').json()); 18 | app.use(require('body-parser').urlencoded({ extended: true })); 19 | 20 | app.use(require('cors')({ 21 | origin: domain 22 | })); 23 | passport.use(new Strategy({ 24 | clientID: "clientID", 25 | clientSecret: "clientSecret", 26 | callbackURL: "callbackURL", 27 | scope: [ "identify", "guilds" ] 28 | }, (accessToken, refreshToken, profile, done) => { 29 | process.nextTick(() => done(null, profile)); 30 | })); 31 | 32 | passport.serializeUser((user, done) => { done(null, user); }); 33 | passport.deserializeUser((obj, done) => { done(null, obj); }); 34 | 35 | app.use(passport.initialize()); 36 | app.use(passport.session()); 37 | 38 | 39 | app.get("/auth/login", (req, res, next) => { 40 | req.session._authCallback = req.query.url || '/'; 41 | next(); 42 | }, passport.authenticate("discord", { 43 | scope: [ "identify", "guilds" ], 44 | prompt: "none" 45 | })); 46 | 47 | app.get("/auth/callback", passport.authenticate("discord", { 48 | failureRedirect: "/auth/login" 49 | }), async (req, res) => { 50 | if (req.user) { 51 | res.redirect(`${domain}/_auth/${req.user.accessToken}`) 52 | } else { 53 | res.redirect('/auth/login'); 54 | }; 55 | }); 56 | 57 | 58 | app.listen(3000) -------------------------------------------------------------------------------- /pages/index.js: -------------------------------------------------------------------------------- 1 | import Head from 'next/head' 2 | import Image from 'next/image' 3 | import { useState, useEffect } from 'react' 4 | import axios from 'axios' 5 | import { API_HOST } from '../config' 6 | import { useRouter } from 'next/router' 7 | const Home = () => { 8 | const [s,i] = useState(false) 9 | const router = useRouter() 10 | const [user,setUser] = useState({}) 11 | useEffect(() => { 12 | (async() => { 13 | let dtoken = window.localStorage.getItem("__nego-auth") 14 | if(!dtoken){ 15 | i(false) 16 | } 17 | let data = await axios.get(`/api/_auth/user?token=${dtoken}`) 18 | if(data.data.status === 401){ 19 | i(false) 20 | } 21 | if(data.data.status === 200){ 22 | i(true) 23 | setUser(data.data) 24 | } 25 | })() 26 | 27 | }) 28 | return ( 29 | <> 30 | {s ?( 31 |
32 |
33 |
34 | 35 |
36 |

ID: {user.id}

37 | 38 |

Username: {user.username}

39 |

Discriminator: {user.discriminator}

40 | 41 |
42 |
43 | ):( 44 |
45 |
46 | 47 |
48 |
49 | )} 50 | 51 | ) 52 | } 53 | 54 | export default Home -------------------------------------------------------------------------------- /.replit: -------------------------------------------------------------------------------- 1 | entrypoint = "index.js" 2 | 3 | hidden = [".config", ".next", ".swc"] 4 | 5 | run = "npm run dev" 6 | 7 | [[hints]] 8 | regex = "Error \\[ERR_REQUIRE_ESM\\]" 9 | message = "We see that you are using require(...) inside your code. We currently do not support this syntax. Please use 'import' instead when using external modules. (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import)" 10 | 11 | [nix] 12 | channel = "stable-21_11" 13 | 14 | [env] 15 | XDG_CONFIG_HOME = "/home/runner/.config" 16 | PATH = "/home/runner/$REPL_SLUG/.config/npm/node_global/bin:/home/runner/$REPL_SLUG/node_modules/.bin" 17 | npm_config_prefix = "/home/runner/$REPL_SLUG/.config/npm/node_global" 18 | 19 | [packager] 20 | language = "nodejs" 21 | 22 | [packager.features] 23 | packageSearch = true 24 | guessImports = true 25 | enabledForHosting = false 26 | 27 | [unitTest] 28 | language = "nodejs" 29 | 30 | [languages.javascript] 31 | pattern = "**/{*.js,*.jsx,*.ts,*.tsx}" 32 | 33 | [languages.javascript.languageServer] 34 | start = [ "typescript-language-server", "--stdio" ] 35 | 36 | [debugger] 37 | support = true 38 | 39 | [debugger.interactive] 40 | transport = "localhost:0" 41 | startCommand = [ "dap-node" ] 42 | 43 | [debugger.interactive.initializeMessage] 44 | command = "initialize" 45 | type = "request" 46 | 47 | [debugger.interactive.initializeMessage.arguments] 48 | clientID = "replit" 49 | clientName = "replit.com" 50 | columnsStartAt1 = true 51 | linesStartAt1 = true 52 | locale = "en-us" 53 | pathFormat = "path" 54 | supportsInvalidatedEvent = true 55 | supportsProgressReporting = true 56 | supportsRunInTerminalRequest = true 57 | supportsVariablePaging = true 58 | supportsVariableType = true 59 | 60 | [debugger.interactive.launchMessage] 61 | command = "launch" 62 | type = "request" 63 | 64 | [debugger.interactive.launchMessage.arguments] 65 | args = [] 66 | console = "externalTerminal" 67 | cwd = "." 68 | environment = [] 69 | pauseForSourceMap = false 70 | program = "./index.js" 71 | request = "launch" 72 | sourceMaps = true 73 | stopOnEntry = false 74 | type = "pwa-node" 75 | --------------------------------------------------------------------------------