> ## 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 (소셜 인증)

> OAuth 2.0을 사용한 소셜 로그인(GitHub, Google, Facebook 등)을 Laravel Socialite로 심플하게 구현하는 방법을 설명합니다.

## Laravel Socialite란

Laravel Socialite는 OAuth 2.0을 사용한 소셜 로그인을 심플하게 구현할 수 있는 공식 패키지입니다. GitHub, Google, Facebook, X(Twitter), LinkedIn 등 주요한 프로바이더에 대응하고 있어, 복잡한 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

각 프로바이더의 클라이언트 ID·시크릿·콜백 URL을 `config/services.php`에 추가합니다.

```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을 작성하면 클라이언트 ID와 시크릿을 취득할 수 있습니다.

***

## 인증 플로우

### 라우팅

OAuth 인증에는 2개의 라우트가 필요합니다. 리다이렉트용과 콜백용입니다.

```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`를 사용하는 경우, `github_id` 컬럼이 `users` 테이블에 존재하고 있어야 합니다. 후술의 마이그레이션 예를 참고해 주세요.
</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);
```

### 스테이트리스 모드

쿠키 세션을 사용하지 않는 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`의 2컬럼 구성이 일반적입니다.

```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는 테스트용의 모크 기능을 제공하고 있습니다. 실제의 프로바이더에의 리퀘스트 없이 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()`로 페이크 사용자를 생성합니다.

```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',
    ]);
});
```

기본적으로 페이크의 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 클래스의 설명](/ko/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 인증과 포스트 송신을 지원.
  </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

- [Socialite for Discord](/ko/packages/socialite-discord.md)
- [Socialite - Laravel Bluesky](/ko/packages/laravel-bluesky/socialite.md)
- [스타터 킷](/ko/starter-kits.md)
- [인증 방식 비교 - Laravel Bluesky](/ko/packages/laravel-bluesky/authentication.md)
- [Socialite (LINE Login) - LINE SDK for Laravel](/ko/packages/laravel-line-sdk/socialite.md)
