Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Mailru Laravel Package

socialiteproviders/mailru

Adds Mail.ru OAuth login to Laravel Socialite. This provider lets your Laravel app authenticate users through Mail.ru using a standard Socialite driver, with configuration for client ID, secret, and redirect URI. Install via Composer and register the provider.

View on GitHub
Deep Wiki
Context7

Getting Started

socialiteproviders/mailru is a thin OAuth 2.0 driver that teaches Laravel Socialite how to talk to Mail.ru (now part of the VK ID ecosystem). It provides endpoints, scope handling, and user mapping — nothing else. Routes, session handling, and user persistence are your responsibility.

Install and register

composer require socialiteproviders/mailru

Socialite does not auto-discover community drivers. Hook the manager's event in AppServiceProvider::boot() (Laravel 11/12) or EventServiceProvider::$listen (Laravel 10 and earlier):

use Illuminate\Support\Facades\Event;
use SocialiteProviders\Manager\SocialiteWasCalled;
use SocialiteProviders\Mailru\Provider;

Event::listen(function (SocialiteWasCalled $event) {
    $event->extendSocialite('mailru', Provider::class);
});

Configure credentials in config/services.php, sourcing from env:

'mailru' => [
    'client_id'     => env('MAILRU_CLIENT_ID'),
    'client_secret' => env('MAILRU_CLIENT_SECRET'),
    'redirect'      => env('MAILRU_REDIRECT_URI'),
],

Register that exact redirect URI in the Mail.ru/VK ID app console. Byte-for-byte match — scheme, host, trailing slash.

First use case — a login button. Two routes and a controller:

Route::get('/auth/mailru/redirect', [MailruAuthController::class, 'redirect']);
Route::get('/auth/mailru/callback', [MailruAuthController::class, 'callback']);
public function redirect()
{
    return Socialite::driver('mailru')->redirect();
}

public function callback()
{
    $mailruUser = Socialite::driver('mailru')->user();

    $user = User::updateOrCreate(
        ['mailru_id' => $mailruUser->getId()],   // never key on email
        [
            'name'   => $mailruUser->getName() ?? $mailruUser->getNickname(),
            'email'  => $mailruUser->getEmail(),
            'avatar' => $mailruUser->getAvatar(),
        ]
    );

    Auth::login($user, remember: true);

    return redirect()->intended('/dashboard');
}

If that works end to end, you have covered the happy path. Everything below is what eats the time in production.

Where to look first when it breaks, in order: (1) the SocialiteWasCalled listener — Driver [mailru] is not supported almost always means it never fired or the key is misspelled; (2) config/services.php plus whether config is cached; (3) the redirect URI registered on the Mail.ru side. Those three account for nearly every incident.

Implementation Patterns

Keep OAuth in a dedicated controller or action class. redirect() and callback() methods on a MailruAuthController, or a LoginWithMailru invokable action. Inlining into routes/web.php is fine for a spike, but state/session handling becomes impossible to test once it's spread across closures.

Separate identity from profile. A social_accounts table (provider, provider_user_id, user_id, token, refresh_token, expires_at) beats per-provider columns on users. It lets you add VK, Yandex, or Google later without a migration each time, and it correctly models one user linking several providers:

$account = SocialAccount::firstOrNew([
    'provider'         => 'mailru',
    'provider_user_id' => $mailruUser->getId(),
]);
$account->user()->associate($user);
$account->fill([
    'token'         => $mailruUser->token,
    'refresh_token' => $mailruUser->refreshToken,
    'expires_at'    => $mailruUser->expiresIn ? now()->addSeconds($mailruUser->expiresIn) : null,
])->save();

Two flows, two shapes. The default redirect/callback flow stores state in the session — correct for browser logins. For API clients, mobile apps, or Livewire/Inertia endpoints where the session may not survive, use stateless mode and carry your own CSRF protection:

return Socialite::driver('mailru')->stateless()->redirect();
// ...
$user = Socialite::driver('mailru')->stateless()->user();

Request scopes at the redirect, not the callback. Only ask for what you'll actually consume:

Socialite::driver('mailru')->setScopes(['email'])->redirect();

Resolve through the container. Socialite::driver('mailru') or app(Socialite::class)->driver('mailru') — never new Provider(...). Instantiating directly bypasses config resolution and the manager's registration, producing failures that look like credential problems.

Wrap the callback in a guard. An unhandled InvalidStateException is a 500 on a page users hit constantly — expired sessions, back button, double-click:

try {
    $mailruUser = Socialite::driver('mailru')->user();
} catch (\Throwable $e) {
    report($e);
    return redirect()->route('login')->with('error', 'Sign-in failed, please try again.');
}

Cache tokens only if you have a refresh path. Mail.ru access tokens are short-lived. A stored token with no refresh flow turns into a confusing 401 inside a background job months later, not at login time where you'd notice it.

Testing at the Socialite boundary. Don't hit the network in tests. Mock the driver call or bind a fake into the container, and build the fake as a Laravel\Socialite\Two\User with setRaw() so getRaw() assertions hold:

$fake = (new \Laravel\Socialite\Two\User)->map([
    'id' => '12345', 'name' => 'Test', 'email' => '[email protected]',
])->setRaw(['user_id' => '12345']);

Socialite::shouldReceive('driver->user')->andReturn($fake);

Custom fields without forking. Subclass the provider, override mapUserToObject(), and register your subclass under a custom key:

Event::listen(function (SocialiteWasCalled $event) {
    $event->extendSocialite('mailru', \App\Support\MailruProvider::class);
});

Integration tips.

  • Adding Mail.ru to an app that already uses Socialite for another provider should reuse the existing controller pattern — keeping Socialite::driver() uniform preserves the ability to swap providers later.
  • Log $user->getRaw() at debug level during bring-up; it contains the actual userinfo response and is the fastest way to see what Mail.ru really returned. Remove it before production — it's personal data.
  • If the app sits behind a proxy or load balancer, confirm TrustProxies so Laravel generates https:// redirect URLs.

Gotchas and Tips

Driver [mailru] is not supported — the SocialiteWasCalled listener is missing, lives in a provider that isn't booted, or the key passed to extendSocialite() doesn't match the string passed to Socialite::driver(). Case matters.

Redirect URI mismatch is the single most common failure. redirect_uri must be identical in config/services.php, the Mail.ru/VK ID console, and the URL the user actually lands on. Watch for http vs https, www vs apex, and trailing slashes. Mismatches surface as invalid_request / invalid_grant.

config:cache will bite you. A cached config silently serving stale credentials looks exactly like a problem on Mail.ru's side. After editing config/services.php or .env, run php artisan config:clear locally and redeploy with a fresh config:cache.

Email is not guaranteed. Phone-only registrations and restricted visibility mean $user->getEmail() can be null. Never use email as the identity key — key on getProviderUserId()/getId(). Treat a null email as "prompt the user to confirm one" rather than inserting '' and tripping a unique index.

Invalid state on callback — expired session, blocked cookies, a different browser, or a stateful redirect paired with a stateless callback. Pick one mode per entry point and stay consistent; in genuinely sessionless contexts use stateless() on both calls.

Scope creep forces re-consent. Adding a scope after launch sends every existing user back through the consent screen. Decide your scope list before you ship. Adding offline-style access later also means tokens you already stored cannot be refreshed.

Patch releases in this monorepo are noise by design. The 4.x line ships frequently with dependency bumps and cross-package syncs; 4.1.1 carries no changelog entry beyond a compare link. Pin the version in composer.json if you want deliberate upgrades, and read the GitHub diff rather than trusting release titles. The real compatibility risk is never the patch number — it's a major bump of laravel/socialite or socialiteproviders/manager, which can change the SocialiteWasCalled signature or the User contract.

Vendor consolidation risk. Mail.ru's consumer identity stack has been folded into VK Group / VK ID. Periodically verify that the endpoints this provider targets are still the officially recommended ones; if the provider is tracking a legacy surface in maintenance mode, that is your largest long-term risk and worth an explicit migration plan.

Extension points worth knowing. extendSocialite() accepts anything implementing SocialiteProviders\Manager\Contracts\ProviderInterface — usually by extending OAuth2\AbstractProvider. You can register several keys (e.g. mailru and mailru-sandbox) pointing at differently configured subclasses. Overriding getAuthUrl(), getTokenUrl(), getUserByToken(), or mapUserToObject() covers nearly every customisation without forking the package.

Maintenance posture. This is a single-provider community repo under the SocialiteProviders org — per-provider attention is thin, and the effective bus factor is the org maintainers. That's acceptable for a driver this small, but budget for reading the source when something breaks rather than expecting upstream fixes on your timeline.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console