├── .editorconfig ├── .env ├── .gitignore ├── README.md ├── app ├── api │ └── auth │ │ └── [...nextauth] │ │ └── route.ts ├── auth-provider.tsx ├── globals.css ├── layout.tsx └── page.tsx ├── components.json ├── components ├── navigation │ ├── auth-buttons.tsx │ └── nav.tsx ├── theme │ ├── theme-provider.tsx │ └── theme-select.tsx └── ui │ ├── avatar.tsx │ ├── button.tsx │ ├── dropdown-menu.tsx │ └── separator.tsx ├── lib ├── prisma.ts └── utils.ts ├── next-auth.d.ts ├── next.config.js ├── package-lock.json ├── package.json ├── postcss.config.js ├── prisma ├── dev.db ├── migrations │ ├── 20230808194533_init │ │ └── migration.sql │ └── migration_lock.toml └── schema.prisma ├── process.d.ts ├── public ├── next.svg └── vercel.svg ├── tailwind.config.js └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | trim_trailing_whitespace = true 8 | indent_style = tab 9 | indent_size = 4 10 | 11 | [*.{yml,md}] 12 | indent_style = space 13 | indent_size = 2 14 | 15 | [*.md] 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | NEXTAUTH_SECRET=2jOHkDR1p9zVVu9d//spFF6nyvi5o+0bbaFXZChJ0f0= 2 | NEXTAUTH_URL=https://9878-5-199-184-16.ngrok-free.app 3 | BOT_TOKEN=6624305292:AAF.... 4 | BOT_USERNAME=monbot 5 | DATABASE_URL="file:./dev.db" 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | node_modules/ 4 | logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | lerna-debug.log* 10 | .yarn-integrity 11 | .npm 12 | 13 | .eslintcache 14 | 15 | *.tsbuildinfo 16 | next-env.d.ts 17 | 18 | .next 19 | .vercel 20 | .env*.local 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Telegram Authentication with NextAuth.js Example 2 | 3 | This example demonstrates how to set up Telegram authentication using NextAuth.js along with other technologies such as Next.js, PrismaJS, Tailwind CSS, and ShadcnUI. 4 | 5 | ## Getting Started 6 | 7 | Follow these steps to get started with the Telegram authentication example: 8 | 9 | 1. **Clone the Repository** 10 | 11 | ```sh 12 | git clone https://github.com/TeaByte/telegram-auth-nextjs.git 13 | cd telegram-auth-nextjs 14 | ``` 15 | 16 | 2. **Install Dependencies** 17 | 18 | ```sh 19 | npm install 20 | ``` 21 | 22 | 3. **Edit the `.env` File** 23 | 24 | Update the `BOT_TOKEN` and `BOT_USERNAME` values in the `.env` file with the data you obtained from [@BotFather](https://t.me/BotFather). 25 | 26 | 4. **Start the Development Server** 27 | 28 | ```sh 29 | npm run dev 30 | ``` 31 | 32 | 5. **Expose Your Local Server with ngrok** 33 | 34 | If you want to test the authentication over the internet, you can use [ngrok](https://ngrok.com/) to expose your local server: 35 | 36 | ```sh 37 | ngrok http 3000 38 | ``` 39 | 40 | Copy the ngrok URL generated and update the `NEXTAUTH_URL` in the `.env.local` file with it. Additionally, send the `/setdomain` command to [@BotFather](https://t.me/BotFather) with the ngrok URL to resolve the "Bot domain invalid" error. 41 | 42 | Remember to replace placeholders and follow the instructions in the example to set up Telegram authentication for your Next.js application. This example combines the power of NextAuth.js, PrismaJS, Tailwind CSS, and ShadcnUI to create a seamless authentication experience using Telegram. 43 | 44 | ![Telegram Authentication Flow](https://i.ibb.co/h1sdVcG/Capture11.jpg) 45 | -------------------------------------------------------------------------------- /app/api/auth/[...nextauth]/route.ts: -------------------------------------------------------------------------------- 1 | import { createUserOrUpdate } from "@/lib/prisma"; 2 | import NextAuth, { NextAuthOptions } from "next-auth"; 3 | import CredentialsProvider from "next-auth/providers/credentials"; 4 | 5 | import { objectToAuthDataMap, AuthDataValidator } from "@telegram-auth/server"; 6 | 7 | declare module "next-auth" { 8 | interface Session { 9 | user: { 10 | id: string; 11 | name: string; 12 | image: string; 13 | email: string; 14 | }; 15 | } 16 | } 17 | 18 | export const authOptions: NextAuthOptions = { 19 | providers: [ 20 | CredentialsProvider({ 21 | id: "telegram-login", 22 | name: "Telegram Login", 23 | credentials: {}, 24 | async authorize(credentials, req) { 25 | const validator = new AuthDataValidator({ 26 | botToken: `${process.env.BOT_TOKEN}`, 27 | }); 28 | 29 | const data = objectToAuthDataMap(req.query || {}); 30 | const user = await validator.validate(data); 31 | 32 | if (user.id && user.first_name) { 33 | const returned = { 34 | id: user.id.toString(), 35 | email: user.id.toString(), 36 | name: [user.first_name, user.last_name || ""].join(" "), 37 | image: user.photo_url, 38 | }; 39 | 40 | try { 41 | await createUserOrUpdate(user); 42 | } catch { 43 | console.log( 44 | "Something went wrong while creating the user." 45 | ); 46 | } 47 | 48 | return returned; 49 | } 50 | return null; 51 | }, 52 | }), 53 | ], 54 | callbacks: { 55 | async session({ session, user, token }) { 56 | session.user.id = session.user.email; 57 | return session; 58 | }, 59 | }, 60 | pages: { 61 | signIn: "/auth/signin", 62 | error: "/auth/error", 63 | }, 64 | }; 65 | 66 | const handler = NextAuth(authOptions); 67 | export { handler as GET, handler as POST }; 68 | -------------------------------------------------------------------------------- /app/auth-provider.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { SessionProvider } from 'next-auth/react'; 4 | 5 | type Props = { 6 | children: React.ReactNode; 7 | }; 8 | 9 | export default function AuthProvider({ children }: Props) { 10 | return {children}; 11 | } -------------------------------------------------------------------------------- /app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer base { 6 | :root { 7 | --background: 0 0% 100%; 8 | --foreground: 0 0% 3.9%; 9 | 10 | --card: 0 0% 100%; 11 | --card-foreground: 0 0% 3.9%; 12 | 13 | --popover: 0 0% 100%; 14 | --popover-foreground: 0 0% 3.9%; 15 | 16 | --primary: 0 0% 9%; 17 | --primary-foreground: 0 0% 98%; 18 | 19 | --secondary: 0 0% 96.1%; 20 | --secondary-foreground: 0 0% 9%; 21 | 22 | --muted: 0 0% 96.1%; 23 | --muted-foreground: 0 0% 45.1%; 24 | 25 | --accent: 0 0% 96.1%; 26 | --accent-foreground: 0 0% 9%; 27 | 28 | --destructive: 0 84.2% 60.2%; 29 | --destructive-foreground: 0 0% 98%; 30 | 31 | --border: 0 0% 89.8%; 32 | --input: 0 0% 89.8%; 33 | --ring: 0 0% 3.9%; 34 | 35 | --radius: 0.5rem; 36 | } 37 | 38 | .dark { 39 | --background: 0 0% 3.9%; 40 | --foreground: 0 0% 98%; 41 | 42 | --card: 0 0% 3.9%; 43 | --card-foreground: 0 0% 98%; 44 | 45 | --popover: 0 0% 3.9%; 46 | --popover-foreground: 0 0% 98%; 47 | 48 | --primary: 0 0% 98%; 49 | --primary-foreground: 0 0% 9%; 50 | 51 | --secondary: 0 0% 14.9%; 52 | --secondary-foreground: 0 0% 98%; 53 | 54 | --muted: 0 0% 14.9%; 55 | --muted-foreground: 0 0% 63.9%; 56 | 57 | --accent: 0 0% 14.9%; 58 | --accent-foreground: 0 0% 98%; 59 | 60 | --destructive: 0 62.8% 30.6%; 61 | --destructive-foreground: 0 0% 98%; 62 | 63 | --border: 0 0% 14.9%; 64 | --input: 0 0% 14.9%; 65 | --ring: 0 0% 83.1%; 66 | } 67 | } 68 | 69 | @layer base { 70 | * { 71 | @apply border-border; 72 | } 73 | body { 74 | @apply bg-background text-foreground; 75 | } 76 | } -------------------------------------------------------------------------------- /app/layout.tsx: -------------------------------------------------------------------------------- 1 | import ThemeProvider from "@/components/theme/theme-provider"; 2 | import Nav from "@/components/navigation/nav"; 3 | 4 | import "./globals.css"; 5 | import type { Metadata } from "next"; 6 | import { Rubik } from "next/font/google"; 7 | 8 | import AuthProvider from "./auth-provider"; 9 | 10 | const font = Rubik({ subsets: ["cyrillic"] }); 11 | export const metadata: Metadata = { 12 | title: "Telegram Auth", 13 | }; 14 | 15 | export default function RootLayout({ 16 | children, 17 | }: { 18 | children: React.ReactNode; 19 | }) { 20 | return ( 21 | 22 | 23 | 24 | 29 |