File size: 5,211 Bytes
74acf19
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Models\User;
use App\Providers\RouteServiceProvider;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;

class GoogleAuthController extends Controller
{
    public function redirect(Request $request): RedirectResponse
    {
        if (! $this->isGoogleLoginConfigured()) {
            return redirect()->route('login')->withErrors([
                'google' => 'Login Google belum dikonfigurasi. Isi GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, dan GOOGLE_REDIRECT_URI terlebih dulu.',
            ]);
        }

        $state = Str::random(40);

        $request->session()->put('google_oauth_state', $state);

        $query = http_build_query([
            'client_id' => (string) config('services.google.client_id'),
            'redirect_uri' => (string) config('services.google.redirect'),
            'response_type' => 'code',
            'scope' => 'openid profile email',
            'prompt' => 'select_account',
            'access_type' => 'offline',
            'state' => $state,
        ]);

        return redirect()->away('https://accounts.google.com/o/oauth2/v2/auth?'.$query);
    }

    public function callback(Request $request): RedirectResponse
    {
        $storedState = (string) $request->session()->pull('google_oauth_state', '');
        $returnedState = (string) $request->string('state');

        if ($request->filled('error')) {
            return redirect()->route('login')->withErrors([
                'google' => 'Login Google dibatalkan atau ditolak oleh pengguna.',
            ]);
        }

        if ($storedState === '' || ! hash_equals($storedState, $returnedState)) {
            return redirect()->route('login')->withErrors([
                'google' => 'Sesi login Google tidak valid. Coba ulangi lagi.',
            ]);
        }

        if (! $this->isGoogleLoginConfigured()) {
            return redirect()->route('login')->withErrors([
                'google' => 'Login Google belum dikonfigurasi di server.',
            ]);
        }

        $tokenResponse = Http::asForm()
            ->timeout(20)
            ->post('https://oauth2.googleapis.com/token', [
                'code' => (string) $request->string('code'),
                'client_id' => (string) config('services.google.client_id'),
                'client_secret' => (string) config('services.google.client_secret'),
                'redirect_uri' => (string) config('services.google.redirect'),
                'grant_type' => 'authorization_code',
            ]);

        if (! $tokenResponse->ok() || ! $tokenResponse->json('access_token')) {
            return redirect()->route('login')->withErrors([
                'google' => 'Google tidak mengembalikan access token yang valid.',
            ]);
        }

        $googleProfile = Http::withToken((string) $tokenResponse->json('access_token'))
            ->timeout(20)
            ->get('https://openidconnect.googleapis.com/v1/userinfo');

        if (! $googleProfile->ok()) {
            return redirect()->route('login')->withErrors([
                'google' => 'Profil akun Google tidak bisa diambil saat ini.',
            ]);
        }

        $profile = $googleProfile->json();
        $googleId = trim((string) data_get($profile, 'sub', ''));
        $email = Str::lower(trim((string) data_get($profile, 'email', '')));

        if ($googleId === '' || $email === '') {
            return redirect()->route('login')->withErrors([
                'google' => 'Data akun Google tidak lengkap. Pastikan email tersedia di akun Google Anda.',
            ]);
        }

        $user = User::query()
            ->where('google_id', $googleId)
            ->orWhere('email', $email)
            ->first();

        if (! $user) {
            $user = User::create([
                'name' => trim((string) data_get($profile, 'name', Str::before($email, '@'))),
                'email' => $email,
                'google_id' => $googleId,
                'email_verified_at' => data_get($profile, 'email_verified') ? Carbon::now() : null,
                'password' => Hash::make(Str::random(40)),
            ]);
        } else {
            $user->forceFill([
                'name' => $user->name ?: trim((string) data_get($profile, 'name', Str::before($email, '@'))),
                'google_id' => $user->google_id ?: $googleId,
            ]);

            if (! $user->email_verified_at && data_get($profile, 'email_verified')) {
                $user->email_verified_at = Carbon::now();
            }

            $user->save();
        }

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

        return redirect()->intended(RouteServiceProvider::HOME);
    }

    private function isGoogleLoginConfigured(): bool
    {
        return filled(config('services.google.client_id'))
            && filled(config('services.google.client_secret'))
            && filled(config('services.google.redirect'));
    }
}