require("dotenv").config();
const express = require("express");
const session = require("express-session");
const helmet = require("helmet");
const crypto = require("crypto");
const { createRemoteJWKSet, jwtVerify } =
require("jose");
const app = express();
const PORT = process.env.PORT || 3000;
const CLIENT_ID = process.env.CLIENT_ID;
const CLIENT_SECRET = process.env.CLIENT_SECRET;
const BASE_URL = process.env.BASE_URL;
const CALLBACK_URL = `${BASE_URL}/auth/callback`;
if (!CLIENT_ID || !CLIENT_SECRET ||
!BASE_URL || !process.env.SESSION_SECRET) {
throw new Error("Missing environment variables");
}
app.use(
helmet({
contentSecurityPolicy: false,
crossOriginOpenerPolicy: {
policy: "same-origin-allow-popups"
}
})
);
app.use(express.urlencoded({ extended: false }));
app.use(
session({
name: "telegram_login_session",
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true,
secure: BASE_URL.startsWith("https://"),
sameSite: "lax",
maxAge: 60 * 60 * 1000
}
})
);
const JWKS = createRemoteJWKSet(
new URL(
"https://oauth.telegram.org/.well-known/jwks.json"
)
);
function randomString() {
return crypto.randomBytes(32).toString("base64url");
}
function createChallenge(verifier) {
return crypto
.createHash("sha256")
.update(verifier)
.digest("base64url");
}
// HOME PAGE
app.get("/", (req, res) => {
const user = req.session.user;
if (user) {
return res.send(`
My Dashboard
Welcome!
${escapeHTML(user.name || "")}
Username:
@${escapeHTML(user.username || "Not available")}
Telegram ID:
${escapeHTML(user.sub || "")}
`);
}
res.send(`
Telegram Login
`);
});
function escapeHTML(value) {
return String(value).replace(/[&<>"']/g, char => ({
"&": "&",
"<": "<",
">": ">",
'"': """,
"'": "'"
})[char]);
}
// START TELEGRAM LOGIN
app.get("/auth/telegram", (req, res) => {
const state = randomString();
const nonce = randomString();
const verifier = randomString();
req.session.oauth = {
state,
nonce,
verifier,
created: Date.now()
};
const challenge = createChallenge(verifier);
const params = new URLSearchParams({
client_id: CLIENT_ID,
redirect_uri: CALLBACK_URL,
response_type: "code",
scope: "openid profile",
state,
nonce,
code_challenge: challenge,
code_challenge_method: "S256"
});
res.redirect(
"https://oauth.telegram.org/auth?" +
params.toString()
);
});
// TELEGRAM CALLBACK
app.get("/auth/callback", async (req, res) => {
try {
const { code, state, error } = req.query;
if (error) {
return res.status(400).send(
"Telegram authorization was cancelled."
);
}
const oauth = req.session.oauth;
if (
!oauth ||
!code ||
!state ||
state !== oauth.state ||
Date.now() - oauth.created > 5 * 60 * 1000
) {
return res.status(400).send(
"Invalid or expired login request."
);
}
// Exchange authorization code
const credentials = Buffer
.from(`${CLIENT_ID}:${CLIENT_SECRET}`)
.toString("base64");
const tokenResponse = await fetch(
"https://oauth.telegram.org/token",
{
method: "POST",
headers: {
"Content-Type":
"application/x-www-form-urlencoded",
"Authorization":
`Basic ${credentials}`
},
body: new URLSearchParams({
grant_type: "authorization_code",
code,
redirect_uri: CALLBACK_URL,
client_id: CLIENT_ID,
code_verifier: oauth.verifier
})
}
);
if (!tokenResponse.ok) {
throw new Error("Token exchange failed");
}
const tokens = await tokenResponse.json();
if (!tokens.id_token) {
throw new Error("Missing ID token");
}
// Verify Telegram ID token
const { payload } = await jwtVerify(
tokens.id_token,
JWKS,
{
issuer: "https://oauth.telegram.org",
audience: CLIENT_ID
}
);
if (
!payload.nonce ||
payload.nonce !== oauth.nonce
) {
throw new Error("Invalid nonce");
}
// Create website session
const user = {
sub: payload.sub,
name: payload.name || "",
username: payload.preferred_username || "",
picture: payload.picture || ""
};
delete req.session.oauth;
req.session.regenerate((err) => {
if (err) {
return res.status(500).send(
"Session error."
);
}
req.session.user = user;
req.session.save((err) => {
if (err) {
return res.status(500).send(
"Could not save session."
);
}
res.redirect("/");
});
});
} catch (error) {
console.error("Login error:", error.message);
res.status(401).send(
"Telegram login failed. Please try again."
);
}
});
// LOGOUT
app.post("/logout", (req, res) => {
req.session.destroy(() => {
res.clearCookie("telegram_login_session");
res.redirect("/");
});
});
// START SERVER
app.listen(PORT, () => {
console.log(
`Website running at ${BASE_URL}`
);
});