sfsso-frappe

Laravel (Socialite)

Laravel punya package Composer khusus (sso-frappe-laravel) yang dibangun di atas Laravel Socialite. PHP tidak bisa import package npm, jadi provider Laravel didistribusi via Composer/Packagist.

Requirements

  • PHP ^8.2
  • Laravel ^11.0|^12.0
  • Laravel Socialite ^5.0

Install

composer require sso-frappe/laravel

Konfigurasi

php artisan vendor:publish --tag=sso-frappe-config
FRAPPE_SSO_BASE_URL=https://erp.example.com
FRAPPE_SSO_CLIENT_ID=<oauth-client-id>
FRAPPE_SSO_CLIENT_SECRET=<oauth-client-secret>
FRAPPE_SSO_REDIRECT_URI=https://app.example.com/auth/frappe/callback

Routes

// routes/web.php
use Laravel\Socialite\Facades\Socialite;

Route::get('/auth/frappe', fn () =>
    Socialite::driver('frappe')->redirect()
)->name('frappe.login');

Route::get('/auth/frappe/callback', function () {
    $frappeUser = Socialite::driver('frappe')->user();

    // Cocokkan/buat user lokal (lihat panduan schema di bawah)
    $identity = \App\Models\UserIdentity::query()
        ->where('provider', 'frappe')
        ->where('provider_subject', $frappeUser->getId())
        ->first();

    // ... link by email, atau buat users + user_identities, lalu Auth::login()
})->name('frappe.callback');

Contoh controller

// app/Http/Controllers/FrappeLoginController.php
namespace App\Http\Controllers;

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

class FrappeLoginController extends Controller
{
    public function __invoke()
    {
        $frappe = Socialite::driver('frappe')->user();

        $user = DB::transaction(function () use ($frappe) {
            // Subject first
            $identity = UserIdentity::query()
                ->where('provider', 'frappe')
                ->where('provider_subject', $frappe->getId())
                ->first();

            if ($identity) {
                return $identity->user;
            }

            // Email fallback — link user manual yang sudah ada
            $user = User::query()->firstOrCreate(
                ['email' => strtolower($frappe->getEmail())],
                [
                    'name' => $frappe->getName(),
                    'password' => null,
                    'status' => 'AKTIF',
                ],
            );

            $user->identities()->create([
                'provider' => 'frappe',
                'provider_subject' => $frappe->getId(),
                'provider_email' => strtolower($frappe->getEmail()),
                'metadata' => [
                    'roles' => $frappe->frappe_roles ?? [],
                ],
            ]);

            return $user;
        });

        abort_unless($user->status === 'AKTIF', 403);

        Auth::login($user, remember: true);
        request()->session()->regenerate();

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

Field profile

Property Source Keterangan
getId() sub Stable subject ID — kunci identitas
getEmail() email Email
getName() name Nama lengkap
getNickname() username Username Frappe
getAvatar() user_image URL avatar
frappe_roles roles Array role
getRaw() Raw userinfo array

Yang di-handle otomatis

  • client_secret_post — Socialite kirim kredensial di POST body (sesuai Frappe)
  • PKCE S256 (aktif default, nonaktif via use_pkce => false)
  • Endpoint eksplisit — tanpa dependency OIDC discovery
  • Normalisasi profile

Schema

Lihat database schema — schema identitas yang direkomendasikan berlaku untuk JS dan Laravel.