1
+ # Laravel Socialite Guidelines
2
+
3
+ Laravel Socialite provides a simple, convenient way to authenticate with OAuth providers like Facebook, Twitter, Google, LinkedIn, GitHub, GitLab, and Bitbucket.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ composer require laravel/socialite
9
+ ```
10
+
11
+ ## Configuration
12
+
13
+ 1. Add OAuth provider credentials to your `.env` file:
14
+
15
+ ```env
16
+ GOOGLE_CLIENT_ID=your-google-client-id
17
+ GOOGLE_CLIENT_SECRET=your-google-client-secret
18
+ GOOGLE_REDIRECT_URL=http://your-app.com/auth/callback/google
19
+
20
+ GITHUB_CLIENT_ID=your-github-client-id
21
+ GITHUB_CLIENT_SECRET=your-github-client-secret
22
+ GITHUB_REDIRECT_URL=http://your-app.com/auth/callback/github
23
+ ```
24
+
25
+ 2. Add the provider configuration to `config/services.php`:
26
+
27
+ ```php
28
+ 'github' => [
29
+ 'client_id' => env('GITHUB_CLIENT_ID'),
30
+ 'client_secret' => env('GITHUB_CLIENT_SECRET'),
31
+ 'redirect' => env('GITHUB_REDIRECT_URL'),
32
+ ],
33
+
34
+ 'google' => [
35
+ 'client_id' => env('GOOGLE_CLIENT_ID'),
36
+ 'client_secret' => env('GOOGLE_CLIENT_SECRET'),
37
+ 'redirect' => env('GOOGLE_REDIRECT_URL'),
38
+ ],
39
+ ```
40
+
41
+ ## Usage Patterns
42
+
43
+ ### Basic Authentication Flow
44
+
45
+ 1. **Redirect to Provider**:
46
+ ```php
47
+ use Laravel\Socialite\Facades\Socialite;
48
+
49
+ Route::get('/auth/redirect/{provider}', function (string $provider) {
50
+ return Socialite::driver($provider)->redirect();
51
+ });
52
+ ```
53
+
54
+ 2. **Handle Provider Callback**:
55
+ ```php
56
+ Route::get('/auth/callback/{provider}', function (string $provider) {
57
+ $user = Socialite::driver($provider)->user();
58
+
59
+ // Find or create user
60
+ $authUser = User::updateOrCreate([
61
+ 'email' => $user->getEmail(),
62
+ ], [
63
+ 'name' => $user->getName(),
64
+ 'provider_id' => $user->getId(),
65
+ 'provider_name' => $provider,
66
+ 'avatar' => $user->getAvatar(),
67
+ ]);
68
+
69
+ Auth::login($authUser);
70
+
71
+ return redirect('/dashboard');
72
+ });
73
+ ```
74
+
75
+ ### User Data Access
76
+
77
+ ```php
78
+ $user = Socialite::driver('github')->user();
79
+
80
+ // Basic info
81
+ $user->getId();
82
+ $user->getNickname();
83
+ $user->getName();
84
+ $user->getEmail();
85
+ $user->getAvatar();
86
+
87
+ // Provider-specific data
88
+ $user->user; // Raw user object from provider
89
+ $user->token; // OAuth token
90
+ $user->refreshToken; // OAuth refresh token (if available)
91
+ $user->expiresIn; // Token expiration time
92
+ ```
93
+
94
+ ### Stateless Authentication
95
+
96
+ For API usage, use stateless authentication:
97
+
98
+ ```php
99
+ $user = Socialite::driver('github')->stateless()->user();
100
+ ```
101
+
102
+ ### Scopes and Parameters
103
+
104
+ Request specific scopes or parameters:
105
+
106
+ ```php
107
+ return Socialite::driver('github')
108
+ ->scopes(['read:user', 'public_repo'])
109
+ ->with(['allow_signup' => 'false'])
110
+ ->redirect();
111
+ ```
112
+
113
+ ## Best Practices
114
+
115
+ ### Database Schema
116
+
117
+ Create a flexible user schema that supports multiple providers:
118
+
119
+ ```php
120
+ Schema::create('users', function (Blueprint $table) {
121
+ $table->id();
122
+ $table->string('name');
123
+ $table->string('email')->unique();
124
+ $table->timestamp('email_verified_at')->nullable();
125
+ $table->string('password')->nullable(); // Nullable for social-only users
126
+ $table->string('provider_name')->nullable();
127
+ $table->string('provider_id')->nullable();
128
+ $table->string('avatar')->nullable();
129
+ $table->rememberToken();
130
+ $table->timestamps();
131
+
132
+ $table->unique(['provider_name', 'provider_id']);
133
+ });
134
+ ```
135
+
136
+ ### User Model
137
+
138
+ ```php
139
+ class User extends Authenticatable
140
+ {
141
+ protected $fillable = [
142
+ 'name',
143
+ 'email',
144
+ 'password',
145
+ 'provider_name',
146
+ 'provider_id',
147
+ 'avatar',
148
+ ];
149
+
150
+ protected $hidden = [
151
+ 'password',
152
+ 'remember_token',
153
+ ];
154
+
155
+ protected $casts = [
156
+ 'email_verified_at' => 'datetime',
157
+ ];
158
+
159
+ public function isSocialUser(): bool
160
+ {
161
+ return !is_null($this->provider_name);
162
+ }
163
+ }
164
+ ```
165
+
166
+ ### Security Considerations
167
+
168
+ 1. **Validate Provider**:
169
+ ```php
170
+ Route::get('/auth/redirect/{provider}', function (string $provider) {
171
+ if (!in_array($provider, ['github', 'google', 'twitter'])) {
172
+ abort(404);
173
+ }
174
+
175
+ return Socialite::driver($provider)->redirect();
176
+ });
177
+ ```
178
+
179
+ 2. **Handle Existing Users**:
180
+ ```php
181
+ Route::get('/auth/callback/{provider}', function (string $provider) {
182
+ $socialUser = Socialite::driver($provider)->user();
183
+
184
+ // Check if user exists with this email but different provider
185
+ $existingUser = User::where('email', $socialUser->getEmail())->first();
186
+
187
+ if ($existingUser && $existingUser->provider_name !== $provider) {
188
+ return redirect('/login')->with('error', 'This email is already registered with a different provider.');
189
+ }
190
+
191
+ // Your user creation logic here
192
+ });
193
+ ```
194
+
195
+ 3. **Rate Limiting**:
196
+ ```php
197
+ Route::get('/auth/redirect/{provider}', function (string $provider) {
198
+ return Socialite::driver($provider)->redirect();
199
+ })->middleware('throttle:6,1');
200
+ ```
201
+
202
+ ### Error Handling
203
+
204
+ ```php
205
+ use Laravel\Socialite\Facades\Socialite;
206
+ use Laravel\Socialite\Two\InvalidStateException;
207
+
208
+ Route::get('/auth/callback/{provider}', function (string $provider) {
209
+ try {
210
+ $user = Socialite::driver($provider)->user();
211
+
212
+ // Handle user logic
213
+
214
+ } catch (InvalidStateException $e) {
215
+ return redirect('/login')->with('error', 'Authentication failed. Please try again.');
216
+ } catch (Exception $e) {
217
+ Log::error('Social login error: ' . $e->getMessage());
218
+ return redirect('/login')->with('error', 'Something went wrong. Please try again.');
219
+ }
220
+ });
221
+ ```
222
+
223
+ ## Custom Providers
224
+
225
+ For custom OAuth providers, extend the abstract provider:
226
+
227
+ ```php
228
+ use Laravel\Socialite\Two\AbstractProvider;
229
+ use Laravel\Socialite\Two\User;
230
+
231
+ class CustomProvider extends AbstractProvider
232
+ {
233
+ protected function getAuthUrl($state)
234
+ {
235
+ return $this->buildAuthUrlFromBase('https://example.com/oauth/authorize', $state);
236
+ }
237
+
238
+ protected function getTokenUrl()
239
+ {
240
+ return 'https://example.com/oauth/token';
241
+ }
242
+
243
+ protected function getUserByToken($token)
244
+ {
245
+ $response = $this->getHttpClient()->get('https://example.com/api/user', [
246
+ 'headers' => [
247
+ 'Authorization' => 'Bearer ' . $token,
248
+ ],
249
+ ]);
250
+
251
+ return json_decode($response->getBody(), true);
252
+ }
253
+
254
+ protected function mapUserToObject(array $user)
255
+ {
256
+ return (new User)->setRaw($user)->map([
257
+ 'id' => $user['id'],
258
+ 'nickname' => $user['username'],
259
+ 'name' => $user['name'],
260
+ 'email' => $user['email'],
261
+ 'avatar' => $user['avatar_url'],
262
+ ]);
263
+ }
264
+ }
265
+ ```
266
+
267
+ ## Testing
268
+
269
+ ### Feature Tests
270
+
271
+ ```php
272
+ use Laravel\Socialite\Facades\Socialite;
273
+ use Laravel\Socialite\Two\User;
274
+
275
+ test('user can login with github', function () {
276
+ $githubUser = Mockery::mock(User::class);
277
+ $githubUser->shouldReceive('getId')->andReturn('123456');
278
+ $githubUser->shouldReceive('getName')->andReturn('John Doe');
279
+ $githubUser->shouldReceive('getEmail')->andReturn('
[email protected] ');
280
+ $githubUser->shouldReceive('getAvatar')->andReturn('https://example.com/avatar.jpg');
281
+
282
+ Socialite::shouldReceive('driver->user')->andReturn($githubUser);
283
+
284
+ $response = $this->get('/auth/callback/github');
285
+
286
+ $response->assertRedirect('/dashboard');
287
+ $this->assertDatabaseHas('users', [
288
+
289
+ 'provider_name' => 'github',
290
+ ]);
291
+ });
292
+ ```
293
+
294
+ ## Common Pitfalls to Avoid
295
+
296
+ 1. **Don't store sensitive tokens in logs**
297
+ 2. **Always validate the provider parameter**
298
+ 3. **Handle email conflicts gracefully**
299
+ 4. **Use HTTPS for redirect URLs in production**
300
+ 5. **Keep provider credentials secure and out of version control**
301
+ 6. **Handle cases where users deny permission**
302
+ 7. **Implement proper session management for the OAuth flow**
0 commit comments