· Admin

Laravel'de Socialite ile Microsoft Hesabıyla Giriş

Kurumsal projelerde "Microsoft ile giriş yap" butonu neredeyse zorunluluk. Şirket çalışanları zaten Microsoft 365 kullanıyor — onlara ayrı bir şifre daha ezberletmek hem UX hem güvenlik açısından kötü fikir. Laravel Socialite ile bu işi birkaç dosyada halledersiniz.

Bu yazıda Azure AD'de uygulama kayıt etmekten, callback handler'a, kullanıcı oluşturma/eşleştirme mantığına kadar her şeyi anlatacağım.

Socialite Nedir?

Laravel Socialite, OAuth sağlayıcılarıyla (Google, Facebook, GitHub, Microsoft, Twitter vs.) sosyal giriş yapmayı kolaylaştıran resmi bir paket. OAuth akışının karmaşık kısımlarını — token exchange, redirect URI, scope yönetimi — sizin yerinize halleder.

Kurulum:

composer require laravel/socialite

Azure Portal'da Uygulama Kaydı

Kod yazmadan önce Microsoft tarafında uygulama kaydı yapmanız gerekiyor:

  1. portal.azure.com → Azure Active Directory → App registrations → New registration
  2. Name: Uygulamanızın adı (ör: "ProjeMan Login")
  3. Supported account types: Projenize göre seçin:
    • Single tenant: Sadece kendi organizasyonunuz (kurumsal intranet)
    • Multitenant: Tüm organizasyonlar (SaaS uygulaması)
    • Multitenant + personal: Hem kurumsal hem kişisel Microsoft hesapları
  4. Redirect URI: http://localhost:8000/auth/microsoft/callback (development için)

Kayıt sonrası şu bilgileri alın:

  • Application (client) ID.env'e MICROSOFT_CLIENT_ID olarak
  • Directory (tenant) ID.env'e MICROSOFT_TENANT_ID olarak

Sonra Certificates & secretsNew client secret ile bir secret oluşturun. Gösterilen değeri hemen kopyalayın — sayfadan çıkınca bir daha göremezsiniz.

Laravel Yapılandırması

.env

MICROSOFT_CLIENT_ID=your-client-id
MICROSOFT_CLIENT_SECRET=your-client-secret
MICROSOFT_REDIRECT_URI=http://localhost:8000/auth/microsoft/callback
MICROSOFT_TENANT=common

MICROSOFT_TENANT seçenekleri:

  • common → Tüm Microsoft hesapları (kişisel + kurumsal)
  • organizations → Sadece kurumsal hesaplar
  • consumers → Sadece kişisel hesaplar (outlook.com, hotmail.com)
  • {tenant-id} → Sadece belirli bir organizasyon

config/services.php

'microsoft' => [
    'client_id' => env('MICROSOFT_CLIENT_ID'),
    'client_secret' => env('MICROSOFT_CLIENT_SECRET'),
    'redirect' => env('MICROSOFT_REDIRECT_URI'),
    'tenant' => env('MICROSOFT_TENANT', 'common'),
],

Migration

Kullanıcı tablosuna Microsoft'a özel alanlar eklememiz gerekiyor:

php artisan make:migration add_microsoft_fields_to_users_table
public function up(): void
{
    Schema::table('users', function (Blueprint $table) {
        $table->string('microsoft_id')->nullable()->unique()->after('email');
        $table->string('microsoft_token')->nullable()->after('microsoft_id');
        $table->string('microsoft_refresh_token')->nullable()->after('microsoft_token');
        $table->string('avatar')->nullable()->after('microsoft_refresh_token');
        $table->string('password')->nullable()->change();
    });
}

password alanını nullable yapıyoruz çünkü Microsoft ile giriş yapan kullanıcının şifresi olmayacak. Eğer hem normal kayıt hem Microsoft girişi destekliyorsanız bu gerekli.

User model'inde fillable'a ekleyin:

protected $fillable = [
    'name',
    'email',
    'password',
    'microsoft_id',
    'microsoft_token',
    'microsoft_refresh_token',
    'avatar',
];

Route'lar

use App\Http\Controllers\MicrosoftAuthController;

Route::get('auth/microsoft', [MicrosoftAuthController::class, 'redirect'])
    ->name('auth.microsoft');

Route::get('auth/microsoft/callback', [MicrosoftAuthController::class, 'callback'])
    ->name('auth.microsoft.callback');

Controller

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Laravel\Socialite\Facades\Socialite;

class MicrosoftAuthController extends Controller
{
    public function redirect()
    {
        return Socialite::driver('microsoft')
            ->scopes(['User.Read'])
            ->redirect();
    }

    public function callback()
    {
        try {
            $microsoftUser = Socialite::driver('microsoft')->user();
        } catch (\Exception $e) {
            return redirect()->route('login')
                ->with('error', 'Microsoft girişi başarısız. Lütfen tekrar deneyin.');
        }

        // Önce microsoft_id ile ara, sonra email ile
        $user = User::where('microsoft_id', $microsoftUser->getId())
            ->orWhere('email', $microsoftUser->getEmail())
            ->first();

        if ($user) {
            // Mevcut kullanıcı — Microsoft bilgilerini güncelle
            $user->update([
                'microsoft_id' => $microsoftUser->getId(),
                'microsoft_token' => $microsoftUser->token,
                'microsoft_refresh_token' => $microsoftUser->refreshToken,
                'avatar' => $microsoftUser->getAvatar(),
            ]);
        } else {
            // Yeni kullanıcı oluştur
            $user = User::create([
                'name' => $microsoftUser->getName(),
                'email' => $microsoftUser->getEmail(),
                'microsoft_id' => $microsoftUser->getId(),
                'microsoft_token' => $microsoftUser->token,
                'microsoft_refresh_token' => $microsoftUser->refreshToken,
                'avatar' => $microsoftUser->getAvatar(),
            ]);
        }

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

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

Callback metodundaki kullanıcı eşleştirme mantığı önemli:

  1. Önce microsoft_id ile arıyoruz — en güvenilir eşleşme
  2. Bulamazsak email ile arıyoruz — kullanıcı daha önce normal kayıt ile hesap açmış olabilir
  3. Hiçbiri yoksa yeni hesap oluşturuyoruz

Bu sıralama sayesinde mevcut kullanıcılar Microsoft hesaplarını bağlayabilir, yeni kullanıcılar da direkt Microsoft ile kayıt olabilir.

try/catch bloğu şart — kullanıcı Microsoft'ta "İptal" derse veya token exchange başarısız olursa uygulama patlamasın.

Login Sayfasına Buton Eklemek

<a href="{{ route('auth.microsoft') }}"
   class="flex items-center justify-center gap-2 w-full border border-gray-300 rounded-lg py-2 px-4 hover:bg-gray-50 transition">
    <svg class="w-5 h-5" viewBox="0 0 21 21">
        <rect x="1" y="1" width="9" height="9" fill="#f25022"/>
        <rect x="11" y="1" width="9" height="9" fill="#7fba00"/>
        <rect x="1" y="11" width="9" height="9" fill="#00a4ef"/>
        <rect x="11" y="11" width="9" height="9" fill="#ffb900"/>
    </svg>
    <span class="text-sm font-medium text-gray-700">Microsoft ile Giriş Yap</span>
</a>

Butonu login formunun altına veya üstüne koyun. Genelde "veya" ayracıyla form ile buton arasına koyarım:

{{-- Normal login formu --}}
<form method="POST" action="{{ route('login') }}">
    {{-- email, password alanları --}}
</form>

<div class="flex items-center my-4">
    <hr class="flex-1 border-gray-300">
    <span class="px-3 text-sm text-gray-500">veya</span>
    <hr class="flex-1 border-gray-300">
</div>

{{-- Microsoft butonu --}}
<a href="{{ route('auth.microsoft') }}" class="...">
    Microsoft ile Giriş Yap
</a>

Diğer Sağlayıcıları da Eklemek

Aynı pattern'i Google ve GitHub için de kullanabilirsiniz. Controller'ı genelleştirmek istiyorsanız:

// routes/web.php
Route::get('auth/{provider}', [SocialAuthController::class, 'redirect'])
    ->whereIn('provider', ['microsoft', 'google', 'github']);

Route::get('auth/{provider}/callback', [SocialAuthController::class, 'callback'])
    ->whereIn('provider', ['microsoft', 'google', 'github']);
// Controller
public function redirect(string $provider)
{
    return Socialite::driver($provider)->redirect();
}

public function callback(string $provider)
{
    $socialUser = Socialite::driver($provider)->user();
    // ... aynı mantık, provider'a göre alan isimleri değişir
}

whereIn kısıtlaması önemli — yoksa birisi /auth/facebook gibi tanımsız bir provider deneyince hata alır.

Production Kontrol Listesi

  • HTTPS zorunlu — Azure Portal'da redirect URI'yi https:// ile kaydedin
  • Redirect URI güncelle — Production domain'inizi Azure Portal'a ekleyin
  • Client secret süresini not edin — Azure secret'lar 6 ay, 12 ay veya 24 ay geçerli. Süresi dolunca login çalışmaz. Takvime hatırlatma koyun
  • Token'ları şifreleyinmicrosoft_token ve microsoft_refresh_token hassas veri. encrypted cast kullanabilirsiniz:
protected function casts(): array
{
    return [
        'microsoft_token' => 'encrypted',
        'microsoft_refresh_token' => 'encrypted',
    ];
}
  • Hata logları — Callback'teki catch bloğunda Log::error() ekleyin
  • Tenant kısıtlaması — Herkese açık olmayacaksa organizations veya specific tenant ID kullanın

Sosyal giriş, kullanıcı deneyimini ciddi şekilde iyileştiriyor. Kayıt formunu doldurmak yerine tek tıkla giriş — conversion rate'i artırır, şifre sıfırlama taleplerini azaltır. Kurumsal projelerde ise neredeyse standart haline geldi.