Skip to content

Instantly share code, notes, and snippets.

@hypernova7
Created August 18, 2022 08:32
Show Gist options
  • Save hypernova7/34d90bd7faefbc9ce8d00279ddb01ddc to your computer and use it in GitHub Desktop.
Save hypernova7/34d90bd7faefbc9ce8d00279ddb01ddc to your computer and use it in GitHub Desktop.
Telegram bot login example using Telegraf v4 and Express
import 'dotenv/config';
import crypto from 'node:crypto';
import express from 'express';
import cookieSession from 'cookie-session';
import { Markup, session, Telegraf } from 'telegraf';
import consola from 'consola';
const logger = consola.withTag('tg-check-auth');
const bot = new Telegraf(process.env.BOT_TOKEN);
const app = express();
bot.use(session());
bot.use((ctx, next) => {
ctx.session = ctx.session || {};
return next();
});
bot.start(ctx => {
const { startPayload } = ctx;
if (startPayload.startsWith('login-')) {
if (startPayload === 'login-fail') {
ctx.session.loginFail = true;
return login(ctx);
}
if (startPayload === `login-${ctx.from.id}`) ctx.reply('You have already logging in');
if (startPayload === 'login-success') ctx.reply('You are logged in');
ctx.session.loggedIn = true;
return;
}
ctx.reply(`Hi ${[ctx.from.first_name, ctx.from.last_name].filter(Boolean).join(' ')}`);
});
bot.command('login', login);
// To use the login button, you need to setup a domain for your bot with @BotFather
async function login (ctx) {
if (ctx.session.loggedIn) return ctx.reply('You have already logging in');
await ctx.replyWithHTML(
!ctx.session.loginFail
? 'Sign In with <b>Telegram</b>'
: 'Something went wrong, please try again or try again later',
{
...Markup.inlineKeyboard([
Markup.button.login('Sign In', 'https://yourdomain.com/auth')
])
}
);
}
// Setup cookie-session
app.use(
cookieSession({
name: 'session',
keys: [process.env.BOT_TOKEN],
maxAge: 24 * 60 * 60 * 1000 // 24 hours
})
);
app.get('/auth', auth);
function auth (req, res) {
let loggedIn = true;
const url = 'https://t.me/yourbotusername?start=login-';
// Use the start parameter to send proof that the user is already logged in
if (req.session.user) // Prevent re-authentication and redirect to the bot
return res.redirect(`${url}${req.session.user}`);
// Authentication
const { auth_date, hash, id } = req.query;
if (auth_date && hash && id) {
const time = Date.now() / 1000;
const authTime = Number.parseInt(auth_date, 10);
const key = crypto.createHash('sha256').update(process.env.BOT_TOKEN).digest();
const data = Object.keys(req.query)
.sort()
.filter(key => key !== 'hash')
.map(key => `${key}=${req.query[key]}`)
.join('\n');
const secret = crypto.createHmac('sha256', key).update(data).digest('hex');
if (hash.localeCompare(secret) === 0 && time - authTime <= 86_400) {
// Set session
req.session.user = id;
logger.success('Successful login');
} else {
loggedIn = false;
}
} else {
loggedIn = false;
}
// Use the start parameter to inform the user if the login was successful or failed
res.redirect(`${url}${loggedIn ? 'success' : 'fail'}`);
}
bot.launch({
// Setup a webhook to use login button. required
webhook: {
domain: 'yourdomain.com',
port: +process.env.PORT,
cb: app // Integrate Express with Telegraf
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment