Skip to content

Commit 9c8c47d

Browse files
committed
feat: Add Laravel Socialite auto-detection and AI guidelines support
This commit introduces automatic detection and comprehensive AI guidelines for the laravel/socialite package, following the established pattern for other Laravel ecosystem packages. Features: - Auto-detection of laravel/socialite in composer.lock - Comprehensive core guidelines covering OAuth flows, security, and best practices - Version 5 specific enhancements with improved error handling - Complete test coverage for detection logic - Updated README documentation
1 parent a18c040 commit 9c8c47d

File tree

5 files changed

+469
-0
lines changed

5 files changed

+469
-0
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Laravel Socialite v5 Specific Guidelines
2+
3+
## Version 5 Enhanced Features
4+
5+
### Improved Error Handling
6+
```php
7+
use Laravel\Socialite\Two\InvalidStateException;
8+
9+
try {
10+
$user = Socialite::driver('github')->user();
11+
} catch (InvalidStateException $e) {
12+
Log::warning('Invalid OAuth state', ['error' => $e->getMessage()]);
13+
return redirect('/login')->with('error', 'Authentication session expired. Please try again.');
14+
}
15+
```
16+
17+
### Type Hints Best Practice
18+
```php
19+
use Laravel\Socialite\Contracts\User as SocialiteUser;
20+
21+
public function handleCallback(string $provider): RedirectResponse
22+
{
23+
$socialiteUser = Socialite::driver($provider)->user();
24+
25+
$user = $this->findOrCreateUser($socialiteUser, $provider);
26+
Auth::login($user);
27+
28+
return redirect()->intended('/dashboard');
29+
}
30+
31+
private function findOrCreateUser(SocialiteUser $socialiteUser, string $provider): User
32+
{
33+
return User::updateOrCreate([
34+
'provider_name' => $provider,
35+
'provider_id' => $socialiteUser->getId(),
36+
], [
37+
'name' => $socialiteUser->getName(),
38+
'email' => $socialiteUser->getEmail(),
39+
'avatar' => $socialiteUser->getAvatar(),
40+
]);
41+
}
42+
```

.ai/laravel-socialite/core.blade.php

Lines changed: 302 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,302 @@
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+
'email' => '[email protected]',
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**

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ Laravel Boost includes AI guidelines for the following packages and frameworks.
6363
|---------|-------------------|
6464
| Core & Boost | core |
6565
| Laravel Framework | core, 10.x, 11.x, 12.x |
66+
| Laravel Socialite | core, 5.x |
6667
| Livewire | core, 2.x, 3.x |
6768
| Filament | core, 4.x |
6869
| Flux UI | core, free, pro |

0 commit comments

Comments
 (0)