azate/laravel-telegram-login-auth
Laravel package that adds Telegram Login authentication to your app. It verifies signed Telegram Login Widget data, integrates with Laravel guards, and lets users sign in via Telegram with configurable routes, middleware, and user provisioning.
Install and publish
composer require azate/laravel-telegram-login-auth
php artisan vendor:publish --provider="Azate\TelegramLoginAuth\TelegramLoginAuthServiceProvider"
This typically publishes a config file (config/telegram-login-auth.php or similar) and possibly a migration for storing Telegram IDs on your users table. Check the vendor/azate/laravel-telegram-login-auth/ directory right after install — with a package this small (37 stars), the README and the source are your best documentation. Read src/ top-to-bottom; it's likely under a dozen files.
Configure credentials
Add your bot credentials to .env:
TELEGRAM_BOT_TOKEN=123456:ABC-DEF...
TELEGRAM_BOT_USERNAME=your_bot_name
The bot token is what the package uses to validate the hash returned by the Telegram Login Widget. The bot username is what renders the widget on your page. These are two different values — don't confuse them.
First use case: log a user in from a Telegram widget
<script> into your login blade, pointing its data-auth-url (or data-onauth handler) at the package's callback route.User, and calls Auth::login().A minimal blade snippet:
<script async src="https://telegram.org/js/telegram-widget.js?22"
data-telegram-login="{{ config('telegram-login-auth.bot_username') }}"
data-size="large"
data-auth-url="{{ route('telegram.login.callback') }}"
data-request-access="write"></script>
If the package ships a route macro or a Socialite-style driver, use it — otherwise bind its service into your own controller and call the verifier directly. Look first at the package's routes/ file and the Http/Controllers namespace to see exactly what it exposes.
Standalone controller integration
The most common pattern for a small package like this is to let the provider handle verification and then dispatch a domain event, or to inject the package's verifier class into your own controller. Prefer the latter for control over user creation:
public function __invoke(TelegramLoginRequest $request, TelegramVerifier $verifier)
{
$payload = $verifier->validate($request->all()); // throws on bad hash
$user = User::firstOrCreate(
['telegram_id' => $payload['id']],
['name' => $payload['first_name'].' '.$payload['last_name'], 'email' => null]
);
Auth::login($user, remember: true);
return redirect()->intended('/dashboard');
}
Pairing with existing auth
Since Telegram does not return an email, the standard pattern is:
id.Extending user creation
If the package exposes a user_model config key (common in similar packages), point it at your own App\Models\User. If it uses a hardcoded model, extend it or override the callback route with your own controller and disable the package's route registration (config('telegram-login-auth.routes.enabled', false)).
Middleware and session
Wrap the callback in web middleware (it needs a session for Auth::login). If you use Sanctum or API tokens, exchange the Telegram verification for a token inside the same controller rather than relying on session state.
Testing pattern
Because the verifier only depends on the bot token, you can fake the hash in tests: compute hash_hmac('sha256', $dataCheckString, hash('sha256', $token, true)) against a dummy token in config(). Assert both the success redirect and the rejection path (tampered auth_date, expired timestamp).
data_check_string must be the URL-decoded key-value pairs sorted alphabetically and joined with \n, excluding hash. If the package accepts the raw request, ensure $request->all() preserves values exactly — Laravel's request normalization can mangle names with special characters.auth_date expiry is on you. Telegram does not expire the widget payload server-side. Reject payloads older than a few minutes (check auth_date against now()) if the package's verifier doesn't. This is a one-line check that prevents replay attacks./setdomain) to the widget's host. If mismatch, the widget loads but auth-url callbacks fail silently — an easy hour to lose.data-auth-url. If the callback is POST and behind VerifyCsrfToken, exempt just that route, or configure data-auth-url as GET and let the package's route handle it.TELEGRAM_BOT_TOKEN is only ever read from config(), not accessed directly in views.env() directly instead of config(), php artisan config:cache will silently zero out the token. Verify in config/telegram-login-auth.php — if any line has env() you'll want to re-cache after every deploy or override with config() in a service provider.register / boot bindings), any published config flags for routes, middleware, user_model, and redirect_to. If these exist, use them instead of forking; for a 37-star package, upstream changes are infrequent, so a thin wrapper controller ages better than a patch.data_check_string and the received hash side by side in a local environment, and diff them character by character — 90% of "hash mismatch" bugs are an extra field, wrong sort order, or URL-encoded characters that weren't decoded.How can I help you explore Laravel packages today?