> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Laravel Socialite（社交登录）

> 介绍如何使用 Laravel Socialite 简洁地实现基于 OAuth 2.0 的社交登录（GitHub、Google、Facebook 等）。

## 什么是 Laravel Socialite

Laravel Socialite 是官方提供的包，用于简洁地实现基于 OAuth 2.0 的社交登录。它已支持 GitHub、Google、Facebook、X（Twitter）、LinkedIn 等主流 OAuth 提供方，只需数行代码就能完成原本复杂的 OAuth 实现。

内置支持的提供方如下：

| 提供方               | 键名                       |
| ----------------- | ------------------------ |
| Bitbucket         | `bitbucket`              |
| Facebook          | `facebook`               |
| GitHub            | `github`                 |
| GitLab            | `gitlab`                 |
| Google            | `google`                 |
| LinkedIn (OpenID) | `linkedin-openid`        |
| Slack             | `slack` / `slack-openid` |
| Spotify           | `spotify`                |
| Twitch            | `twitch`                 |
| X (Twitter)       | `x`                      |

### 社交登录的流程

```mermaid theme={null}
sequenceDiagram
    participant User as 用户
    participant App as Laravel 应用
    participant OAuth as GitHub (OAuth)
    participant DB as 数据库

    User->>App: 点击登录按钮
    App->>OAuth: 重定向 (Socialite::driver('github')->redirect())
    OAuth->>User: 认证与授权页面
    User->>OAuth: 同意
    OAuth->>App: 回调（带 code 参数）
    App->>OAuth: 换取访问令牌
    OAuth-->>App: 返回用户信息
    App->>DB: 使用 updateOrCreate 注册 / 更新用户
    DB-->>App: 用户记录
    App->>User: 登录成功，跳转到仪表盘
```

***

## 安装

使用 Composer 安装：

```shell theme={null}
composer require laravel/socialite
```

<Info>
  升级 Socialite 大版本时请务必查看[升级指南](https://github.com/laravel/socialite/blob/master/UPGRADE.md)。
</Info>

***

## 配置

### config/services.php

在 `config/services.php` 中添加各提供方的客户端 ID、密钥及回调 URL。

```php theme={null}
// config/services.php

'github' => [
    'client_id' => env('GITHUB_CLIENT_ID'),
    'client_secret' => env('GITHUB_CLIENT_SECRET'),
    'redirect' => env('GITHUB_REDIRECT_URI'),
],

'google' => [
    'client_id' => env('GOOGLE_CLIENT_ID'),
    'client_secret' => env('GOOGLE_CLIENT_SECRET'),
    'redirect' => env('GOOGLE_REDIRECT_URI'),
],

'facebook' => [
    'client_id' => env('FACEBOOK_CLIENT_ID'),
    'client_secret' => env('FACEBOOK_CLIENT_SECRET'),
    'redirect' => env('FACEBOOK_REDIRECT_URI'),
],
```

<Info>
  在 `redirect` 中使用相对路径时会被自动解析为完整 URL。
</Info>

### .env

通过环境变量管理凭据。下面以 GitHub 为例：

```ini theme={null}
GITHUB_CLIENT_ID=your-client-id
GITHUB_CLIENT_SECRET=your-client-secret
GITHUB_REDIRECT_URI=https://example.com/auth/github/callback
```

在 GitHub 中，可以在 [GitHub Developer Settings](https://github.com/settings/developers) 创建 OAuth App 来获得 Client ID 与密钥。

***

## 认证流程

### 路由

OAuth 认证需要两个路由：一个用于重定向，一个用于回调。

```php theme={null}
use Laravel\Socialite\Facades\Socialite;

// 将用户重定向到 GitHub
Route::get('/auth/github', function () {
    return Socialite::driver('github')->redirect();
});

// 处理来自 GitHub 的回调
Route::get('/auth/github/callback', function () {
    $user = Socialite::driver('github')->user();

    // 通过 $user->token 获取访问令牌
});
```

### 保存用户并登录

在回调路由中获取用户信息，保存到数据库后登录。

```php theme={null}
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Laravel\Socialite\Facades\Socialite;

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

    $user = User::updateOrCreate(
        ['github_id' => $githubUser->id],
        [
            'name' => $githubUser->name,
            'email' => $githubUser->email,
            'github_token' => $githubUser->token,
            'github_refresh_token' => $githubUser->refreshToken,
        ]
    );

    Auth::login($user);

    return redirect('/dashboard');
});
```

<Warning>
  使用 `updateOrCreate` 时，`users` 表中必须存在 `github_id` 列。请参考后文的迁移示例。
</Warning>

***

## 获取用户信息

`user()` 方法返回的对象包含如下属性和方法。

```php theme={null}
Route::get('/auth/github/callback', function () {
    $user = Socialite::driver('github')->user();

    // OAuth 2.0 提供方
    $token = $user->token;
    $refreshToken = $user->refreshToken;
    $expiresIn = $user->expiresIn;

    // OAuth 1.0 提供方（如 X）
    $token = $user->token;
    $tokenSecret = $user->tokenSecret;

    // 所有提供方通用
    $user->getId();
    $user->getNickname();
    $user->getName();
    $user->getEmail();
    $user->getAvatar();
});
```

### 通过访问令牌获取用户

如果已有访问令牌，可用 `userFromToken()` 获取用户信息。

```php theme={null}
$user = Socialite::driver('github')->userFromToken($token);
```

### 无状态模式

对于不使用 Cookie Session 的 API，可以通过 `stateless()` 关闭状态校验。

```php theme={null}
return Socialite::driver('google')->stateless()->user();
```

***

## 数据库集成

### 迁移

向 `users` 表添加用于社交登录的列。

```php theme={null}
// database/migrations/xxxx_xx_xx_add_github_columns_to_users_table.php

return new class extends Migration
{
    public function up(): void
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('github_id')->nullable()->unique()->after('id');
            $table->string('github_token')->nullable()->after('github_id');
            $table->string('github_refresh_token')->nullable()->after('github_token');
        });
    }

    public function down(): void
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn(['github_id', 'github_token', 'github_refresh_token']);
        });
    }
};
```

### 使用 provider 列支持多个提供方

若要统一管理多个提供方，通常使用 `provider` / `provider_id` 两列。

```php theme={null}
Schema::table('users', function (Blueprint $table) {
    $table->string('provider')->nullable()->after('id');
    $table->string('provider_id')->nullable()->after('provider');
    $table->string('provider_token')->nullable()->after('provider_id');

    $table->unique(['provider', 'provider_id']);
});
```

回调处理时动态传入提供方名称。

```php theme={null}
Route::get('/auth/{provider}/callback', function (string $provider) {
    $socialUser = Socialite::driver($provider)->user();

    $user = User::updateOrCreate(
        [
            'provider' => $provider,
            'provider_id' => $socialUser->getId(),
        ],
        [
            'name' => $socialUser->getName(),
            'email' => $socialUser->getEmail(),
            'provider_token' => $socialUser->token,
        ]
    );

    Auth::login($user);

    return redirect('/dashboard');
});
```

### 与已有用户关联

若要将账户与拥有同邮箱的已有用户关联，可以先按邮箱查找，再更新对应列。

```php theme={null}
$socialUser = Socialite::driver('github')->user();

$user = User::where('email', $socialUser->getEmail())->first();

if ($user) {
    // 将 GitHub 信息关联到已有用户
    $user->update([
        'github_id' => $socialUser->getId(),
        'github_token' => $socialUser->token,
    ]);
} else {
    // 作为新用户创建
    $user = User::create([
        'name' => $socialUser->getName(),
        'email' => $socialUser->getEmail(),
        'github_id' => $socialUser->getId(),
        'github_token' => $socialUser->token,
    ]);
}

Auth::login($user);
```

***

## 作用域与选项

### 添加作用域

使用 `scopes()` 方法可以追加作用域。

```php theme={null}
return Socialite::driver('github')
    ->scopes(['read:user', 'public_repo'])
    ->redirect();
```

`setScopes()` 会覆盖原有的所有作用域。

```php theme={null}
return Socialite::driver('github')
    ->setScopes(['read:user', 'public_repo'])
    ->redirect();
```

### 可选参数

使用 `with()` 方法可以在重定向请求中附加额外参数。

```php theme={null}
// 在 Google 中限制托管域
return Socialite::driver('google')
    ->with(['hd' => 'example.com'])
    ->redirect();

// 在 Google 中每次都显示授权页面
return Socialite::driver('google')
    ->with(['prompt' => 'consent'])
    ->redirect();
```

<Warning>
  请勿通过 `with()` 传递 `state`、`response_type` 等保留关键字。
</Warning>

### Slack Bot 令牌

要生成 Slack Bot 令牌，可以使用 `asBotUser()`。

```php theme={null}
// 重定向时
return Socialite::driver('slack')
    ->asBotUser()
    ->setScopes(['chat:write', 'chat:write.public', 'chat:write.customize'])
    ->redirect();

// 回调时
$user = Socialite::driver('slack')->asBotUser()->user();
```

***

## 测试

Socialite 提供了 mock 机制，可以在不真的调用提供方接口的情况下测试 OAuth 流程。

### 测试重定向

```php theme={null}
use Laravel\Socialite\Facades\Socialite;

test('用户被重定向到 GitHub', function () {
    Socialite::fake('github');

    $response = $this->get('/auth/github');

    $response->assertRedirect();
});
```

### 测试回调

向 `fake()` 传入用户实例，即可模拟从提供方返回的用户信息。可以用 `User::fake()` 生成 fake 用户。

```php theme={null}
use Laravel\Socialite\Facades\Socialite;
use Laravel\Socialite\Two\User;

test('可以通过 GitHub 登录', function () {
    Socialite::fake('github', User::fake([
        'id' => 'github-123',
        'name' => 'Jane Doe',
        'email' => 'jane@example.com',
    ]));

    $response = $this->get('/auth/github/callback');

    $response->assertRedirect('/dashboard');

    $this->assertDatabaseHas('users', [
        'name' => 'Jane Doe',
        'email' => 'jane@example.com',
        'github_id' => 'github-123',
    ]);
});
```

默认会设置 fake 的 OAuth 令牌，如需覆盖可在 `fake()` 中传入更多属性。

```php theme={null}
$fakeUser = User::fake([
    'id' => 'github-123',
    'name' => 'Jane Doe',
    'email' => 'jane@example.com',
    'token' => 'fake-token',
    'refreshToken' => 'fake-refresh-token',
    'expiresIn' => 3600,
    'approvedScopes' => ['read:user', 'public_repo'],
]);
```

如果要伪造 OAuth 1 用户，请使用 `Laravel\Socialite\One\User` 类。

***

## 自定义提供方

如果内置提供方无法满足需求，官方推荐的做法是使用 `Socialite::extend()` 注册自定义驱动。`SocialiteManager` 继承自 `Illuminate\Support\Manager`，可以与其他 Laravel 驱动系统采用相同的方式进行扩展。

<Info>
  关于 Manager 模式与 `extend()` 的机制，也可参考 [Manager 类解析](/zh/advanced/manager)。
</Info>

### 1. 创建提供方类

继承 `Laravel\Socialite\Two\AbstractProvider`，实现 4 个抽象方法。

```php theme={null}
// app/Socialite/ExampleProvider.php

namespace App\Socialite;

use Laravel\Socialite\Two\AbstractProvider;
use Laravel\Socialite\Two\User;

class ExampleProvider extends AbstractProvider
{
    // 授权 URL（用户被重定向到的地方）
    public function getAuthUrl($state): string
    {
        return $this->buildAuthUrlFromBase('https://example.com/oauth/authorize', $state);
    }

    // 获取访问令牌的 URL
    protected function getTokenUrl(): string
    {
        return 'https://example.com/oauth/token';
    }

    // 使用访问令牌获取用户信息
    protected function getUserByToken($token): array
    {
        $response = $this->getHttpClient()->get('https://example.com/api/user', [
            'headers' => ['Authorization' => 'Bearer '.$token],
        ]);

        return json_decode($response->getBody(), true);
    }

    // 将数组映射为 Socialite 的 User 对象
    protected function mapUserToObject(array $user): User
    {
        return (new User)->setRaw($user)->map([
            'id'       => $user['id'],
            'nickname' => $user['login'] ?? null,
            'name'     => $user['name'],
            'email'    => $user['email'],
            'avatar'   => $user['avatar_url'] ?? null,
        ]);
    }
}
```

需要实现的 4 个方法的作用如下。

| 方法                             | 作用                           |
| ------------------------------ | ---------------------------- |
| `getAuthUrl($state)`           | 返回将用户重定向到的 OAuth 授权 URL      |
| `getTokenUrl()`                | 将授权码换取为访问令牌的端点               |
| `getUserByToken($token)`       | 使用访问令牌调用用户信息 API，并以数组返回      |
| `mapUserToObject(array $user)` | 将数组转换为 Socialite 的 `User` 对象 |

### 2. 在服务提供者中注册

在 `AppServiceProvider` 的 `boot()` 中通过 `Socialite::extend()` 注册驱动。

```php theme={null}
// app/Providers/AppServiceProvider.php

use App\Socialite\ExampleProvider;
use Laravel\Socialite\Facades\Socialite;

public function boot(): void
{
    Socialite::extend('example', function ($app) {
        $config = $app['config']['services.example'];

        return Socialite::buildProvider(ExampleProvider::class, $config);
    });
}
```

### 3. 添加配置

```php theme={null}
// config/services.php
'example' => [
    'client_id'     => env('EXAMPLE_CLIENT_ID'),
    'client_secret' => env('EXAMPLE_CLIENT_SECRET'),
    'redirect'      => env('EXAMPLE_REDIRECT_URI'),
],
```

### 4. 像普通 Socialite 一样使用

注册完成后就可以像内置提供方一样使用完全相同的 API。

```php theme={null}
// 重定向
Route::get('/auth/example', function () {
    return Socialite::driver('example')->redirect();
});

// 回调
Route::get('/auth/example/callback', function () {
    $user = Socialite::driver('example')->user();
});
```

<Tip>
  使用第三方通过 `extend()` 正规扩展 Socialite 的包也是不错的选择。
</Tip>

***

## 相关包

以下是本站作者维护的 Socialite 扩展包。它们都通过 `Socialite::extend()` 的规范方式实现，只需在 `config/services.php` 中加入配置即可使用。

<CardGroup cols={2}>
  <Card title="LINE" icon="comment" href="https://github.com/invokable/laravel-line-sdk">
    LINE SDK for Laravel。除 Socialite 的 OAuth 登录外，还集成了 Messaging API。
  </Card>

  <Card title="Bluesky" icon="cloud" href="https://github.com/invokable/laravel-bluesky">
    与 AT Protocol（Bluesky）集成，支持 OAuth 认证与发送 Post。
  </Card>

  <Card title="Discord" icon="discord" href="https://github.com/invokable/socialite-discord">
    Discord OAuth2 登录。
  </Card>

  <Card title="Threads" icon="instagram" href="https://github.com/invokable/laravel-threads">
    与 Meta Threads 集成，支持 OAuth 认证与发帖 API。
  </Card>

  <Card title="Amazon" icon="amazon" href="https://github.com/invokable/socialite-amazon">
    通过 Login with Amazon 实现 OAuth 登录。
  </Card>

  <Card title="Mastodon" icon="mastodon" href="https://github.com/invokable/socialite-mastodon">
    连接到 Mastodon 实例的 OAuth 登录。
  </Card>

  <Card title="WordPress" icon="wordpress" href="https://github.com/invokable/socialite-wordpress">
    WordPress.com 或自托管 WordPress 的 OAuth 登录。
  </Card>
</CardGroup>


## Related topics

- [启动套件](/zh/starter-kits.md)
- [Socialite for Discord](/zh/packages/socialite-discord.md)
- [Socialite - Laravel Bluesky](/zh/packages/laravel-bluesky/socialite.md)
- [认证方式对比 - Laravel Bluesky](/zh/packages/laravel-bluesky/authentication.md)
- [Bot 教程 - Laravel Bluesky](/zh/packages/laravel-bluesky/bot-tutorial.md)
