Telegram OAuth Authorization for Your Site
Tags: tutorial, go, php, node
Published: 2023-03-24 14:42:27

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:

```shell
https://oauth.telegram.org/auth?bot_id=YOUR_BOT_ID&scope=YOUR_SCOPE&public_key=YOUR_PUBLIC_KEY&nonce=YOUR_NONCE
```

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
<?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
// ...

?>
```

## Node.js Example:

```javascript
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

```

## Golang Example:

```go
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))
}

```

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.