DEV Community

Cover image for Telegram OAuth Authorization for Your Site
Alex Awesome
Alex Awesome

Posted on • Edited on

Telegram OAuth Authorization for Your Site

You can make authorization via Telegram another way. It works. But today we want to do the classic OAuth Authorization.
Before you begin, you need to create a Telegram bot and obtain your bot token. You can do this in @BotFather in Telegram. For more information on initiating a bot, read the Telegram Bot API documentation: https://core.telegram.org/bots

Redirect Users to Telegram's OAuth URL

To initiate the OAuth process, you'll need to redirect users to the following URL:

https://oauth.telegram.org/auth?bot_id=YOUR_BOT_ID&scope=YOUR_SCOPE&public_key=YOUR_PUBLIC_KEY&nonce=YOUR_NONCE
Enter fullscreen mode Exit fullscreen mode

You have to replace YOUR_BOT_ID, YOUR_SCOPE, YOUR_PUBLIC_KEY, and YOUR_NONCE with your bot's specific information. The nonce is a unique, randomly generated string that you'll need to store for later validation.

Handle Telegram's OAuth Callback

After the user authorizes your application, Telegram will redirect them back to your site with a URL that contains a hash and a payload. You'll need to verify the hash, parse the payload, and store the user's information.
That's it! I could wrap up this article. But ok, I am going to add the examples in languages that I use: PHP, Node.js, and Golang.

PHP Example:

<?php

$botToken = 'YOUR_BOT_TOKEN';

// Extracting the hash and payload from the request
$hash = $_GET['hash'];
$payload = json_decode(base64_decode($_GET['payload']), true);

// Verifying the hash
$secretKey = hash('sha256', $botToken, true);
$checkHash = hash_hmac('sha256', $payload, $secretKey);

if ($hash !== $checkHash) {
    die('Invalid hash.');
}

// Extracting user information from the payload
$user = $payload['user'];
$userId = $user['id'];
$firstName = $user['first_name'];
$lastName = $user['last_name'];
$username = $user['username'];

// Store user information in your database
// ...

?>
Enter fullscreen mode Exit fullscreen mode

Node.js Example:

const crypto = require('crypto');
const url = require('url');
const querystring = require('querystring');

const botToken = 'YOUR_BOT_TOKEN';

const handleTelegramOAuthCallback = (req, res) => {
  const parsedUrl = url.parse(req.url);
  const queryParams = querystring.parse(parsedUrl.query);

  const hash = queryParams.hash;
  const payload = JSON.parse(Buffer.from(queryParams.payload, 'base64').toString());

  const secretKey = crypto.createHash('sha256').update(botToken).digest();
  const checkHash = crypto.createHmac('sha256', secretKey).update(queryParams.payload).digest('hex');

  if (hash !== checkHash) {
    res.status(400).send('Invalid hash');
    return;
  }

  const user = payload.user;
  const userId = user.id;
  const firstName = user.first_name;
  const lastName = user.last_name;
  const username = user.username;

  // Store user information in your database
  // ...
};

// Use the handleTelegramOAuthCallback function as a request handler in your web server

Enter fullscreen mode Exit fullscreen mode

Golang Example:

package main

import (
 "crypto/hmac"
 "crypto/sha256"
 "encoding/base64"
 "encoding/hex"
 "encoding/json"
 "log"
 "net/http"
)

const (
 botToken  = "YOUR_BOT_TOKEN"
)

type User struct {
 Id        int64  `json:"id"`
 FirstName string `json:"first_name"`
 LastName  string `json:"last_name"`
 Username  string `json:"username"`
}

type Payload struct {
 User User `json:"user"`
}

func handleTelegramOAuthCallback(w http.ResponseWriter, r *http.Request) {
 hash := r.URL.Query().Get("hash")
 payloadB64 := r .URL.Query().Get("payload")
 payloadBytes, err := base64.StdEncoding.DecodeString(payloadB64)
 if err != nil {
  http.Error(w, "Invalid payload", http.StatusBadRequest)
  return
 }

 var payload Payload
 err = json.Unmarshal(payloadBytes, &payload)
 if err != nil {
  http.Error(w, "Invalid payload", http.StatusBadRequest)
  return
 }

 h := hmac.New(sha256.New, []byte(botToken))
 h.Write([]byte(payloadB64))
 checkHash := hex.EncodeToString(h.Sum(nil))

 if hash != checkHash {
  http.Error(w, "Invalid hash", http.StatusBadRequest)
  return
 }

 user := payload.User
 userId := user.Id
 firstName := user.FirstName
 lastName := user.LastName
 username := user.Username

 // Store user information in your database
 // ...
}

func main() {
 http.HandleFunc("/telegram-oauth-callback", handleTelegramOAuthCallback)

 log.Fatal(http.ListenAndServe(":8080", nil))
}

Enter fullscreen mode Exit fullscreen mode

It's very easy, isn't it?
Of course, these are not the best blocks of code ever, but they help to understand how to work with it.

Top comments (8)

Collapse
 
mistval profile image
Randall

Thanks for this, I managed to get this working, but I'm curious where you learned about this feature. I can't find it anywhere in the Telegram developer documentation. I can only find discussion of the login widget there, no discussion of redirecting to the oauth.telegram.org domain like this.

Collapse
 
outranker profile image
Justin

after verifying the payload and saving user data how do we authenticate user's next requests to the server? does telegram provide some sort of session or access tokens? if so how do we update/refresh them? it looks like this is an unfinished concept from telegram's side

Collapse
 
sandeep_web3 profile image
Sandeep Narahari

one doubt here , i order to do the oauth , how can we get the hash and payload , i mean where can i get that , per the code , I think i need to give the hash and payload in query parameters, but not finding the way where can i get that , Please correct me , if am wrong

Thank you

http://localhost:8080/telegram-oauth-callback?hash=yourHashValue&payload=yourBase64Payload

Collapse
 
sandeep_web3 profile image
Sandeep Narahari

from where do we get the public key

Collapse
 
mxlison profile image
mxlison • Edited

Create privKey using openssl genrsa 2048 > private.key, then use openssl rsa -in private.key -pubout to display pubKey, afterwards setup your pub key to bot, in @botfather using /setpublickey and send printed pubkey in format:

-----BEGIN PUBLIC KEY-----
YOUR PUBKEY
-----END PUBLIC KEY-----
Enter fullscreen mode Exit fullscreen mode

You can read this docs for better understanding Passport auth: core.telegram.org/passport

Collapse
 
shaggyrec profile image
Alex Awesome

Read this post, please core.telegram.org/bots . It's enough to understand how to create telegram bots

Collapse
 
sandeep_web3 profile image
Sandeep Narahari

I didn't find anywhere named public key, could you please share exactly where your referring to

Thank you

Thread Thread
 
shaggyrec profile image
Alex Awesome

You are totally right. The article was translated and I don't remember where publicKey is from.

I've corrected the post