skip to content

In Laravel, how do you add GitHub sign-in with Socialite, from the config/services.php entry to the callback route?

level: juniorimportance: must knowfreq 55%

answer

  1. three keys under services.github
  2. two routes: out and back
  3. redirect() returns a RedirectResponse
  4. user() swaps the code for a token
  5. Laravel\Socialite\Two\User with getId()

basics

~10 s

Add a github entry with client_id, client_secret and redirect to config/services.php, then define two routes: one returning Socialite::driver('github')->redirect(), and a callback calling ->user() to get the provider user you map to a local account.

solid answer

~40 s

After `composer require laravel/socialite`, add a `github` entry to `config/services.php` with `client_id`, `client_secret` and `redirect`, reading the secrets from `.env`; a missing key throws `DriverMissingConfigurationException`, and a relative `redirect` such as `/auth/github/callback` is turned into a full URL. The first route returns `Socialite::driver('github')->redirect()`, which stores a random `state` in the session and sends the browser to GitHub. The callback route calls `Socialite::driver('github')->user()`: it checks the returned `state`, exchanges the `code` for an access token, fetches the profile and returns a `Laravel\Socialite\Two\User` with `getId()`, `getNickname()`, `getName()`, `getEmail()`, `getAvatar()`, plus `token`, `refreshToken`, `expiresIn` and `approvedScopes`. You then find or create the local user keyed on the provider id and sign them in. Both routes must run with sessions, so they belong in `routes/web.php`.

code

php · 20 lines
php
<?php

use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;
use Laravel\Socialite\Socialite;

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

    $member = User::updateOrCreate(
        ['github_id' => $githubUser->getId()],
        ['name' => $githubUser->getName() ?? $githubUser->getNickname(),
         'email' => $githubUser->getEmail()],
    );

    Auth::login($member);

    return redirect('/feed');
});

go deeper

for a junior

Recall the three services.php keys, the two routes, and that redirect() sends the user away while user() returns a provider user you still have to map and sign in.

for a middle

Explain what redirect() and user() do underneath: state in the session, code for token exchange, profile fetch, and which fields the returned user carries.

for a senior

Point out the failure modes: sessionless routes, mismatched callback hosts, a redirect value that differs from the provider registration, and null emails.

for a principal

Decide which providers the product should offer and whether social login replaces or sits beside password accounts.

## What Socialite is **Laravel Socialite** (`laravel/socialite`) is the first-party package that lets a Laravel app act as an **OAuth client**: it sends a visitor to a provider such as GitHub or Google, receives them back, and turns the provider's answer into a user object. It does not create accounts or sign anyone in; that stays your code. Built-in drivers include `github`, `google`, `gitlab`, `bitbucket`, `facebook`, `linkedin-openid`, `slack`, `slack-openid` and `x`. ## Step 1: configuration For a developer-community site offering "Sign in with GitHub", register an OAuth app in GitHub's developer settings and copy its credentials into `.env`. Then add an entry to `config/services.php` (the skeleton's file has no `github` key yet): ```php 'github' => [ 'client_id' => env('GITHUB_CLIENT_ID'), 'client_secret' => env('GITHUB_CLIENT_SECRET'), 'redirect' => '/auth/github/callback', ], ``` - The **config key must match the driver name**: `Socialite::driver('github')` reads `services.github`. - All three keys are **required**. If one is missing, the manager throws `Laravel\Socialite\Exceptions\DriverMissingConfigurationException` naming the missing keys. - A `redirect` value that starts with `/` is passed through `url()` and becomes absolute; it must match the callback URL registered with the provider. - An optional `scopes` array in the same entry is added to the driver's default scopes. ## Step 2: the two routes ```php use Laravel\Socialite\Socialite; Route::get('/auth/github/redirect', fn () => Socialite::driver('github')->redirect()); Route::get('/auth/github/callback', function () { $githubUser = Socialite::driver('github')->user(); // map to a local account, then sign in }); ``` What each call does: 1. `redirect()` generates a random 40-character `state`, stores it in the **session** under `state`, builds GitHub's authorize URL with `client_id`, `redirect_uri`, `scope`, `response_type=code` and `state`, and returns an `Illuminate\Http\RedirectResponse`. 2. The member approves on GitHub and is sent back with `code` and `state` in the query string. 3. `user()` pulls `state` from the session and compares it with the query value; a mismatch throws `Laravel\Socialite\Two\InvalidStateException`. 4. It posts the `code` to GitHub's token endpoint, receives an access token, calls GitHub's user API and maps the result. ## Step 3: the user object | Member | Meaning | |---|---| | `getId()` | the provider's stable user id; key your link on this | | `getNickname()`, `getName()` | GitHub login and display name | | `getEmail()` | may be null; with the default `user:email` scope, the GitHub driver returns the primary **verified** address | | `getAvatar()` | avatar URL | | `token`, `refreshToken`, `expiresIn` | the OAuth tokens from the exchange | | `approvedScopes` | the scopes the provider says it granted | | `getRaw()` / `user` | the raw profile array | ## Step 4: mapping and signing in The callback looks the member up by provider and provider id, creates a record if none exists, and then signs them in with the session guard. Keying on `getId()` rather than on the email matters: emails change and can be missing, while the id is stable. The skeleton's `users` table was designed for password accounts, so social login usually needs schema work first: - a column or separate table for the provider id, with a unique index; - a nullable `password`, because a member who only ever uses GitHub has none; - a nullable `email` if you accept members without a public, verified address; - the new columns added to the model's `#[Fillable]` list, or `updateOrCreate()` silently drops them. ## Adding Google as well A second provider is another `config/services.php` entry (`google`) and usually one pair of routes with a `{provider}` parameter. Validate that parameter against an allow-list such as `['github', 'google']` before calling `Socialite::driver($provider)`: an unknown name makes the manager throw `InvalidArgumentException`, and a configured-but-unintended driver would otherwise be reachable too. ## Common mistakes - Putting the callback in `routes/api.php`, where there is no session: `redirect()` and `user()` then fail with "Session store not set on request." - Registering `http://localhost` with the provider but browsing on `127.0.0.1`, so the callback lands on a different cookie domain and the state is missing. - Registering a callback URL with the provider that differs from the `redirect` value, so the provider refuses the request before the member sees the consent screen. - Assuming `getEmail()` always returns a value.

  • What happens if config/services.php has a github entry without a redirect key?
    `SocialiteManager::buildProvider()` checks for `client_id`, `client_secret` and `redirect`, and throws `DriverMissingConfigurationException` listing the missing keys as soon as `Socialite::driver('github')` is resolved. The error appears on the redirect route, before any request reaches GitHub.
  • Why must both Socialite routes run inside the web middleware group?
    `redirect()` writes the `state` into the session and `user()` reads it back, so both need the session started by the web group. In `routes/api.php` there is no session, and the first `session()` call throws a `RuntimeException` ("Session store not set on request.") instead of a clean OAuth error.

Socialite is like a hotel front desk that checks guests in with a passport issued elsewhere: it sends you to the issuing office, takes the stamped reply you bring back and reads your details off it. Deciding which room you get, and whether you are the same guest as last week, is still the hotel's job.

saying these in an interview costs you the question

  • Socialite creates the local user and logs them in automatically
  • Socialite::driver('github') reads its credentials from config/auth.php
  • getEmail() always returns an address for GitHub users
  • The callback route can live in routes/api.php like any other endpoint
  • Matching members by email is the documented way to key GitHub logins