├── .eslintrc.json ├── src ├── app │ ├── globals.css │ ├── favicon.ico │ ├── api │ │ └── auth │ │ │ └── [kindeAuth] │ │ │ └── route.js │ ├── layout.tsx │ ├── page.tsx │ ├── admin-area │ │ └── page.tsx │ └── dashboard │ │ └── page.tsx ├── components │ ├── question-delete-button.tsx │ ├── ask-question-form.tsx │ ├── questions-list.tsx │ └── sidebar.tsx ├── lib │ └── db.ts └── actions │ └── actions.ts ├── postcss.config.js ├── .env.example ├── next.config.js ├── prisma └── schema.prisma ├── README.md ├── .gitignore ├── tailwind.config.ts ├── public ├── vercel.svg └── next.svg ├── tsconfig.json └── package.json /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ByteGrad/kinde-nextjs-auth/HEAD/src/app/favicon.ico -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /src/app/api/auth/[kindeAuth]/route.js: -------------------------------------------------------------------------------- 1 | import { handleAuth } from "@kinde-oss/kinde-auth-nextjs/server"; 2 | 3 | export const GET = handleAuth(); 4 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | DATABASE_URL= 2 | 3 | KINDE_CLIENT_ID= 4 | KINDE_CLIENT_SECRET= 5 | KINDE_ISSUER_URL= 6 | 7 | KINDE_SITE_URL= 8 | KINDE_POST_LOGOUT_REDIRECT_URL= 9 | KINDE_POST_LOGIN_REDIRECT_URL= -------------------------------------------------------------------------------- /src/components/question-delete-button.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { deleteQuestion } from "@/actions/actions"; 4 | import React from "react"; 5 | 6 | export default function QuestionDeleteButton({ id }: { id: number }) { 7 | return ( 8 | 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | images: { 4 | remotePatterns: [ 5 | { 6 | protocol: "https", 7 | hostname: "avatars.githubusercontent.com", 8 | }, 9 | { 10 | protocol: "https", 11 | hostname: "lh3.googleusercontent.com", 12 | }, 13 | ], 14 | }, 15 | }; 16 | 17 | module.exports = nextConfig; 18 | -------------------------------------------------------------------------------- /prisma/schema.prisma: -------------------------------------------------------------------------------- 1 | // This is your Prisma schema file, 2 | // learn more about it in the docs: https://pris.ly/d/prisma-schema 3 | 4 | generator client { 5 | provider = "prisma-client-js" 6 | } 7 | 8 | datasource db { 9 | provider = "sqlite" 10 | url = env("DATABASE_URL") 11 | } 12 | 13 | model Question { 14 | id Int @id @default(autoincrement()) 15 | text String 16 | kindeAuthId String 17 | } 18 | -------------------------------------------------------------------------------- /src/lib/db.ts: -------------------------------------------------------------------------------- 1 | import { PrismaClient } from "@prisma/client"; 2 | 3 | const prismaClientSingleton = () => { 4 | return new PrismaClient(); 5 | }; 6 | 7 | type PrismaClientSingleton = ReturnType; 8 | 9 | const globalForPrisma = globalThis as unknown as { 10 | prisma: PrismaClientSingleton | undefined; 11 | }; 12 | 13 | const prisma = globalForPrisma.prisma ?? prismaClientSingleton(); 14 | 15 | export default prisma; 16 | 17 | if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma; 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is a starter repo for Next.js + Kinde Auth. It deals with authentication in server components, server actions, client components and roles & permissions. 2 | 3 | No guarantees are given that it's coded 100% securely, but it's a good starting point. 4 | 5 | ## Getting Started 6 | 7 | Run 'npm install' to install all the dependencies. 8 | 9 | Create a .env file with the environment variables given as an example in .env.example -- after that you can delete the .env.example file. 10 | 11 | Run 'npx prisma db push' to create the database and tables. 12 | -------------------------------------------------------------------------------- /.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 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | .env 31 | 32 | # vercel 33 | .vercel 34 | 35 | # typescript 36 | *.tsbuildinfo 37 | next-env.d.ts 38 | 39 | dev.db -------------------------------------------------------------------------------- /tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'tailwindcss' 2 | 3 | const config: Config = { 4 | content: [ 5 | './src/pages/**/*.{js,ts,jsx,tsx,mdx}', 6 | './src/components/**/*.{js,ts,jsx,tsx,mdx}', 7 | './src/app/**/*.{js,ts,jsx,tsx,mdx}', 8 | ], 9 | theme: { 10 | extend: { 11 | backgroundImage: { 12 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', 13 | 'gradient-conic': 14 | 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', 15 | }, 16 | }, 17 | }, 18 | plugins: [], 19 | } 20 | export default config 21 | -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/ask-question-form.tsx: -------------------------------------------------------------------------------- 1 | import { addQuestion } from "@/actions/actions"; 2 | 3 | export default function AskQuestionForm() { 4 | return ( 5 |
6 |