UNPKG

gebeya-telegram-otp

Version:

Reusable Telegram phone verification components for React applications

514 lines (398 loc) 14.5 kB
# Installation Guide for Gebeya Telegram OTP This guide will walk you through installing and setting up the `gebeya-telegram-otp` package in your React application. ## Step 1: Install the NPM Package ```bash npm install gebeya-telegram-otp ``` ## Step 2: Install Peer Dependencies The package requires several peer dependencies. Install them all at once: ```bash npm install @supabase/supabase-js lucide-react input-otp sonner qrcode react react-dom ``` ### Individual Peer Dependencies If you prefer to install them individually or need specific versions: ```bash # Supabase client for database operations npm install @supabase/supabase-js # Icons for the UI (supports versions 0.300.0 and above) npm install lucide-react # OTP input component npm install input-otp # Toast notifications npm install sonner # QR code generation npm install qrcode # React (supports React 17+ and 18+) npm install react react-dom ``` **Note:** This package uses flexible version ranges (`>=`) to ensure compatibility with both older and newer versions of dependencies. Your existing versions should work fine if they meet the minimum requirements. ## Step 3: Set Up Tailwind CSS The components use Tailwind CSS for styling. If you don't have Tailwind CSS set up, follow these steps: ### Install Tailwind CSS ```bash npm install -D tailwindcss postcss autoprefixer npx tailwindcss init -p ``` ### Configure Tailwind CSS Update your `tailwind.config.js` to include the package components: ```javascript /** @type {import('tailwindcss').Config} */ module.exports = { content: [ "./index.html", "./src/**/*.{js,ts,jsx,tsx}", "./node_modules/gebeya-telegram-verify/dist/**/*.{js,ts,jsx,tsx}", ], theme: { extend: {}, }, plugins: [], }; ``` ### Add Tailwind directives Add these directives to your main CSS file (e.g., `src/index.css`): ```css @tailwind base; @tailwind components; @tailwind utilities; ``` ## Step 4: Set Up Supabase ### Create a Supabase Project 1. Go to [https://supabase.com](https://supabase.com) 2. Create a new project 3. Note your project URL and anon key ### Set Up the Database Run this SQL in your Supabase SQL editor: ```sql -- Create verification sessions table CREATE TABLE public.verification_sessions ( id UUID NOT NULL DEFAULT gen_random_uuid() PRIMARY KEY, phone_number TEXT NOT NULL, telegram_user_id BIGINT, telegram_chat_id BIGINT, otp_code TEXT, verified BOOLEAN NOT NULL DEFAULT false, expires_at TIMESTAMP WITH TIME ZONE NOT NULL, created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now() ); -- Enable RLS ALTER TABLE public.verification_sessions ENABLE ROW LEVEL SECURITY; -- Create policies CREATE POLICY "Anyone can insert verification sessions" ON public.verification_sessions FOR INSERT WITH CHECK (true); CREATE POLICY "Anyone can read verification sessions for verification process" ON public.verification_sessions FOR SELECT USING (true); CREATE POLICY "Anyone can update verification sessions" ON public.verification_sessions FOR UPDATE USING (true); ``` ### Create Supabase Client Create a file `src/lib/supabase.js` (or `.ts` for TypeScript): ```javascript import { createClient } from "@supabase/supabase-js"; const supabaseUrl = "YOUR_SUPABASE_URL"; const supabaseKey = "YOUR_SUPABASE_ANON_KEY"; export const supabase = createClient(supabaseUrl, supabaseKey); ``` ## Step 5: Set Up Telegram Bot 1. Message [@BotFather](https://t.me/botfather) on Telegram 2. Create a new bot with `/newbot` 3. Get your bot token 4. Add the bot token to your Supabase secrets as `TELEGRAM_BOT_TOKEN` ## Step 6: Configure Edge Functions ### Add Edge Functions Configuration In your `supabase/config.toml`, add: ```toml [functions.telegram-webhook] verify_jwt = false [functions.verify-otp] verify_jwt = false ``` ### Create Edge Functions Create these edge functions in your `supabase/functions/` directory: #### Telegram Webhook (`supabase/functions/telegram-webhook/index.ts`) ```typescript import { serve } from "https://deno.land/std@0.168.0/http/server.ts"; import { createClient } from "https://esm.sh/@supabase/supabase-js@2"; const corsHeaders = { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type", }; serve(async (req) => { if (req.method === "OPTIONS") { return new Response(null, { headers: corsHeaders }); } try { const requestBody = await req.json(); const botToken = Deno.env.get("TELEGRAM_BOT_TOKEN"); const supabaseUrl = Deno.env.get("SUPABASE_URL"); const supabaseKey = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY"); if (!botToken || !supabaseUrl || !supabaseKey) { return new Response( JSON.stringify({ error: "Missing required environment variables" }), { status: 500, headers: corsHeaders } ); } const supabase = createClient(supabaseUrl, supabaseKey); // Handle webhook setup if (requestBody.action === "setup_webhook") { const webhookUrl = `${supabaseUrl}/functions/v1/telegram-webhook`; const telegramApiUrl = `https://api.telegram.org/bot${botToken}/setWebhook`; const response = await fetch(telegramApiUrl, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ url: webhookUrl }), }); const result = await response.json(); return new Response(JSON.stringify(result), { headers: { ...corsHeaders, "Content-Type": "application/json" }, }); } // Handle verification session creation if (requestBody.phone_number && !requestBody.message) { const { data: session, error } = await supabase .from("verification_sessions") .insert({ phone_number: requestBody.phone_number, expires_at: new Date(Date.now() + 10 * 60 * 1000).toISOString(), }) .select() .single(); if (error) { return new Response( JSON.stringify({ error: "Failed to create verification session" }), { status: 500, headers: corsHeaders } ); } return new Response(JSON.stringify({ session_id: session.id }), { headers: corsHeaders, }); } // Handle Telegram updates (messages, contacts, etc.) const update = requestBody; if (update.message?.contact) { const contact = update.message.contact; const chatId = update.message.chat.id; const userId = update.message.from.id; const phoneNumber = contact.phone_number.startsWith("+") ? contact.phone_number : "+" + contact.phone_number; // Generate OTP const otpCode = Math.floor(100000 + Math.random() * 900000).toString(); // Update verification session await supabase .from("verification_sessions") .update({ telegram_user_id: userId, telegram_chat_id: chatId, otp_code: otpCode, expires_at: new Date(Date.now() + 5 * 60 * 1000).toISOString(), }) .eq("phone_number", phoneNumber); // Send OTP to user await fetch(`https://api.telegram.org/bot${botToken}/sendMessage`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ chat_id: chatId, text: `Your OTP code is: ${otpCode}`, reply_markup: { remove_keyboard: true }, }), }); } return new Response("OK", { headers: corsHeaders }); } catch (error) { console.error("Webhook error:", error); return new Response("Internal Server Error", { status: 500, headers: corsHeaders, }); } }); ``` #### OTP Verification (`supabase/functions/verify-otp/index.ts`) ```typescript import { serve } from "https://deno.land/std@0.168.0/http/server.ts"; import { createClient } from "https://esm.sh/@supabase/supabase-js@2"; const corsHeaders = { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type", }; serve(async (req) => { if (req.method === "OPTIONS") { return new Response(null, { headers: corsHeaders }); } try { const { phone_number, otp_code } = await req.json(); if (!phone_number || !otp_code) { return new Response( JSON.stringify({ error: "Phone number and OTP are required" }), { status: 400, headers: corsHeaders } ); } const supabaseUrl = Deno.env.get("SUPABASE_URL"); const supabaseKey = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY"); if (!supabaseUrl || !supabaseKey) { return new Response( JSON.stringify({ error: "Server configuration error" }), { status: 500, headers: corsHeaders } ); } const supabase = createClient(supabaseUrl, supabaseKey); // Verify OTP const { data: session, error } = await supabase .from("verification_sessions") .select("*") .eq("phone_number", phone_number) .eq("otp_code", otp_code) .eq("verified", false) .gt("expires_at", new Date().toISOString()) .single(); if (error || !session) { return new Response(JSON.stringify({ error: "Invalid or expired OTP" }), { status: 400, headers: corsHeaders, }); } // Mark as verified await supabase .from("verification_sessions") .update({ verified: true }) .eq("id", session.id); // Create or update user const { data: user, error: userError } = await supabase.auth.admin.createUser({ phone: phone_number, phone_confirm: true, user_metadata: { phone_verified: true, telegram_user_id: session.telegram_user_id, }, }); return new Response( JSON.stringify({ success: true, message: "Phone number verified successfully", user: user?.user, }), { headers: corsHeaders } ); } catch (error) { console.error("Verification error:", error); return new Response(JSON.stringify({ error: "Internal server error" }), { status: 500, headers: corsHeaders, }); } }); ``` ## Step 7: Set Up Environment Variables In your Supabase Dashboard > Settings > Edge Functions, add: - `TELEGRAM_BOT_TOKEN`: Your bot token from Step 5 ## Step 8: Set Up Webhook Set your bot webhook by calling your edge function: ```bash curl -X POST "https://YOUR_PROJECT_ID.supabase.co/functions/v1/telegram-webhook" \ -H "Content-Type: application/json" \ -d '{"action": "setup_webhook"}' ``` ## Step 9: Integration ### Basic Setup ```tsx // In your main App.tsx or layout file import { TelegramVerificationProvider } from "gebeya-telegram-otp"; import { supabase } from "./lib/supabase"; function App() { return ( <TelegramVerificationProvider supabaseClient={supabase} telegramConfig={{ botName: "@your_bot_name" }} onSuccess={(userData) => { console.log("Verification successful:", userData); }} onError={(error) => { console.error("Verification error:", error); }} > <YourAppContent /> </TelegramVerificationProvider> ); } export default App; ``` ### Using the Verification Button ```tsx import { TelegramVerifyButton } from "gebeya-telegram-otp"; function LoginPage() { return ( <div className="flex items-center justify-center min-h-screen"> <div className="p-8 max-w-md mx-auto"> <h1 className="text-2xl font-bold mb-6 text-center">Sign In</h1> <TelegramVerifyButton buttonText="Verify with Telegram" variant="default" size="lg" className="w-full" onVerificationComplete={(userData) => { console.log("User verified:", userData); // Redirect to dashboard or update app state }} /> </div> </div> ); } export default LoginPage; ``` ### TypeScript Support The package includes full TypeScript definitions: ```tsx import { TelegramVerifyButton, TelegramVerificationProvider, type TelegramVerificationData, type TelegramConfig, } from "gebeya-telegram-otp"; // Types are automatically available const config: TelegramConfig = { botName: "@your_bot_name", }; const handleSuccess = (userData: TelegramVerificationData) => { // userData is fully typed console.log("User ID:", userData.user.id); console.log("Phone:", userData.user.phone); }; ``` ## Verification Complete! 🎉 Your application should now be ready to use Telegram verification. The package will handle: - Phone number input with country selection - QR code generation for Telegram verification - OTP verification process - Success handling ## Troubleshooting ### Common Issues 1. **Missing styles**: Ensure Tailwind CSS is properly configured with the package path 2. **Supabase errors**: Check your database setup and RLS policies 3. **Telegram bot issues**: Verify your bot token and webhook setup 4. **Import errors**: Make sure all peer dependencies are installed 5. **Edge function errors**: Check your Supabase function logs for detailed error messages ### Debug Steps 1. Check Supabase edge function logs in your dashboard 2. Test webhook manually with curl 3. Verify database entries in verification_sessions table 4. Check Telegram bot settings with [@BotFather](https://t.me/botfather) 5. Ensure all environment variables are properly set ## Security Considerations 1. Never expose bot token in client-side code 2. Implement rate limiting for verification attempts 3. Set appropriate session expiry times 4. Use HTTPS for all webhook URLs 5. Validate phone numbers on both client and server ## Next Steps - Customize styling to match your app - Add additional security measures - Implement user profiles - Add multi-language support - Set up monitoring and analytics For more detailed setup instructions, see the [setup-guide.md](./setup-guide.md) file.