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

Auth Yandex Laravel Package

baks-dev/auth-yandex

Yandex ID authorization module for BaksDev. Install with composer require baks-dev/auth-yandex, create a Yandex ID app with redirect to /auth/yandex, set YANDEX_CLIENT_ID and YANDEX_CLIENT_SECRET in .env, then install assets and run migrations.

View on GitHub
Deep Wiki
Context7

Getting Started

What you're actually installing: baks-dev/auth-yandex is a Symfony bundle (v7.4.6, PHP 8.4+), not a Laravel package. The README's install steps are composer require, php bin/console baks:assets:install, and doctrine:migrations:* — those are Symfony commands. There is no ServiceProvider, no config/auth.php driver, no Blade views, and no Artisan surface. Treat it as the reference implementation of the Yandex ID OAuth2 flow you'll re-express in Laravel — or bridge it behind a Symfony kernel if you already run one. Don't expect composer require to "just work."

Day-one sequence:

composer require baks-dev/auth-yandex
# Immediately inspect what landed:
ls vendor/baks-dev/auth-yandex/src
cat vendor/baks-dev/auth-yandex/composer.json   # confirm php>=8.4 and baks-dev/core dep

Then:

  1. Register the Yandex ID app. Yandex console → Бизнес → Яндекс ID для сайта → create app → set the redirect URI to https://<DOMAIN>/auth/yandex exactly (scheme, host, trailing slash). This string is hard-coded into the bundle's route; if it disagrees, Yandex returns a bare invalid_request.
  2. Set env:
    YANDEX_CLIENT_ID=...
    YANDEX_CLIENT_SECRET=...
    
    Then grep -r YANDEX_CLIENT_ID vendor/baks-dev/auth-yandex to confirm how the bundle reads them (env vs. config/packages/*.yaml param bag). Symfony bundles often don't read $_ENV directly.
  3. Read the source in this order — the README is a stub, so the code is the spec:
    • src/Controller/ — the /auth/yandex route, redirect URI construction, state handling
    • src/Security/ or src/OAuth/ — the token exchange and /info profile fetch
    • Migrations/ — the exact Doctrine schema for the identity link
    • vendor/baks-dev/core/ — the user entity the Yandex identity attaches to
  4. Run the package's own tests — the only real spec:
    vendor/bin/phpunit --group=auth-yandex
    
    On a Laravel-only app this will need the Symfony test harness; if it won't boot, skip it and read the test files instead.
  5. First usable outcome: "Sign in with Yandex" button → redirect to Yandex → callback hit → Auth::login($user) → dashboard. Ship that before touching roles, account linking, or refresh tokens.

Where to look first, in one sentence: read vendor/baks-dev/auth-yandex/src and Migrations/, not the README — the README only covers install and env.

Implementation Patterns

Pattern 1 — Re-implement the flow in Laravel (recommended)

The bundle's job is ~150 lines of Yandex OAuth2. Port it. You keep Laravel's session, routing, and CSRF, and you don't babysit a Symfony kernel.

// routes/web.php
Route::get('/auth/yandex', [YandexController::class, 'redirect'])->name('auth.yandex');
Route::get('/auth/yandex/callback', [YandexController::class, 'callback']);

// config/services.php
'yandex' => [
    'client_id'     => env('YANDEX_CLIENT_ID'),
    'client_secret' => env('YANDEX_CLIENT_SECRET'),
    'redirect'      => env('APP_URL') . '/auth/yandex',
],
public function redirect()
{
    $state = Str::random(40);
    session(['yandex_state' => $state]);

    return redirect()->away('https://oauth.yandex.ru/authorize?' . http_build_query([
        'response_type' => 'code',
        'client_id'     => config('services.yandex.client_id'),
        'redirect_uri'  => config('services.yandex.redirect'),
        'state'         => $state,
    ]));
}

public function callback(Request $request)
{
    abort_unless(hash_equals(session()->pull('yandex_state'), (string) $request->state), 403);

    $token = Http::asForm()->post('https://oauth.yandex.ru/token', [
        'grant_type'    => 'authorization_code',
        'code'          => $request->code,
        'client_id'     => config('services.yandex.client_id'),
        'client_secret' => config('services.yandex.client_secret'),
        'redirect_uri'  => config('services.yandex.redirect'),
    ])->throw()->json();

    $profile = Http::withToken($token['access_token'])
        ->get('https://login.yandex.ru/info', ['format' => 'json'])
        ->throw()->json();

    $user = $this->linkOrCreate($profile);   // Pattern 3
    Auth::login($user, remember: true);

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

The endpoint URLs, format=json, and the state handling should be mirrored from the vendor source — don't guess them from memory.

Pattern 2 — Side-by-side Symfony kernel (only if you already run Symfony components)

If your monorepo already has a Symfony kernel, mount the bundle and proxy the callback so Laravel stays the front controller. Configure the bundle's YAML against the same YANDEX_* env vars so the two sides can't drift. The handshake between Symfony and Laravel must be credential-free — pass a signed "authenticated as yandex_id" assertion, never the access token. For most Laravel shops this is overkill; Pattern 1 wins.

Pattern 3 — Identity linking as a pivot table, keyed on yandex_id

The bundle's Doctrine migration typically attaches a Yandex row to a user. Mirror it as a pivot, not columns on users:

Schema::create('yandex_identities', function (Blueprint $table) {
    $table->id();
    $table->foreignId('user_id')->constrained()->cascadeOnDelete();
    $table->string('yandex_id')->unique();   // stable key — not email
    $table->string('email')->nullable();
    $table->boolean('email_verified')->default(false);
    $table->timestamps();
});
protected function linkOrCreate(array $profile): User
{
    if ($identity = YandexIdentity::where('yandex_id', $profile['id'])->first()) {
        return $identity->user;
    }

    return DB::transaction(function () use ($profile) {
        $user = User::firstWhere('email', $profile['default_email'] ?? null);

        if ($user) {
            // Same email, different provider: require confirmation, do NOT silently link.
            // An attacker controlling that Yandex mailbox would inherit the account.
            session(['pending_yandex_link' => $profile]);
            return $user; // caller redirects to a "confirm link" step
        }

        $user = User::create([
            'name'     => $profile['real_name'] ?? $profile['display_name'],
            'email'    => $profile['default_email'] ?? null,
            'password' => Hash::make(Str::random(64)),
        ]);
        $user->yandexIdentities()->create(['yandex_id' => $profile['id']]);
        return $user;
    });
}

Key on yandex_id, never on email — Yandex users can change default_email and can carry multiple aliases.

Pattern 4 — Keep tokens out of session/cookies

Mirror the bundle's server-side storage. Cache tokens keyed by user, refresh on expiry, never hand them to Blade:

Cache::put("yandex:token:{$user->id}", [
    'access'     => $token['access_token'],
    'expires_at' => now()->addSeconds($token['expires_in']),
], now()->addSeconds($token['expires_in']));

Pattern 5 — Feature-test the whole flow

Nothing in the package tests your integration. Fake Yandex and assert outcomes:

Http::fake([
    'oauth.yandex.ru/token' => Http::response(['access_token' => 'tok', 'expires_in' => 3600]),
    'login.yandex.ru/info*' => Http::response(['id' => '42', 'default_email' => '[email protected]']),
]);

$this->withSession(['yandex_state' => 'st'])
     ->get('/auth/yandex/callback?code=abc&state=st')
     ->assertRedirect(route('dashboard'));

$this->assertAuthenticated();
$this->assertDatabaseHas('yandex_identities', ['yandex_id' => '42']);

Separate tests for: bad state, error=access_denied from Yandex, email collision with a non-Yandex account, and a second login for an existing yandex_id (must not create a duplicate).

Gotchas and Tips

It is not a Laravel package. No ServiceProvider, no auto-discovery, no config/auth.php driver, no Artisan commands. composer require succeeding tells you nothing runs. Budget half a day to read vendor/baks-dev/auth-yandex/src and Migrations/ before writing a line — the README covers install and env only.

php bin/console ≠ php artisan. baks:assets:install, doctrine:migrations:diff, and doctrine:migrations:migrate need a Symfony kernel and Doctrine. On a pure Laravel app they'll either fail with "command not defined" or silently no-op. Read the Doctrine migration by hand and translate it to an artisan make:migration.

PHP 8.4 minimum is a hard blocker. v7.4.6 pins php 8.4+. On 8.2/8.3 Composer resolves to nothing (or an older tag) — that's silent. Check composer why baks-dev/auth-yandex and composer show baks-dev/auth-yandex right after install.

Doctrine → Eloquent translation is not 1:1. Doctrine string defaults to 255, timestamps are datetime rather than timestamp, unique-index naming differs. After migrating, verify the unique index on yandex_id exists — its absence produces duplicate-user bugs that only show up under concurrent registration.

Redirect URI must match byte-for-byte. Yandex checks scheme, host, port, trailing slash, and any locale prefix. A mismatch surfaces as a bare invalid_request with no detail — the fix is in the Yandex console, not the code. In local dev use a real host (https://app.test/auth/yandex via Herd/Valet) rather than http://localhost; some providers reject plain http.

Always validate state with hash_equals and session()->pull(). The bundle does this internally; your bridge must too. Pull-and-forget on read prevents replay. Missing state validation is a CSRF on your login endpoint.

Never link by email without confirmation. If a Yandex default_email matches an existing local account, silently attaching the identity means anyone who controls that Yandex mailbox inherits the account. Safe default: create the identity pending-confirmation, email the user a link, and only complete the link on click.

Don't trust default_email as a primary key. It can change and may be absent (Yandex can return an account with no mail). Handle null email in the migration (already nullable() above) and in the login flow — you may need to prompt for an email after the first login.

Env loading quirk to check first: grep for YANDEX_CLIENT_ID and getenv in vendor. If the bundle reads from a Symfony parameter bag (config/packages/baks_auth_yandex.yaml), setting .env alone will do nothing — you'll need to feed the value through the kernel or bypass the bundle and use Pattern 1.

Testing against the bundle is nearly useless in a Laravel app. vendor/bin/phpunit --group=auth-yandex boots Symfony's test kernel; if that's not wired, skip it and read the test bodies for the exact endpoint URLs, scope string (login:email, login:info), and payload shape. Those values are the only thing you need from the tests.

Version pin to a minor. Releases (7.4.5, 7.4.6) look trivial but this is a 0-star, single-maintainer package. Pin baks-dev/auth-yandex:^7.4 and baks-dev/core:^7.4 explicitly; a surprise minor could change route paths or env var names without a changelog.

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.
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names