Skip to main content
Version: CANARY 🚧

Authentication via social networks

Introduction​

A social network authentication package for BowPHP. It lets your users sign in with their existing social accounts instead of creating yet another password. Under the hood the package wraps thephpleague/oauth2-client and drives the standard OAuth 2.0 authorization code flow for you:

  1. Your app redirects the user to the provider's consent screen.
  2. The user approves, and the provider calls back to your app with a code.
  3. The package exchanges that code for an access token and returns the authenticated user as a UserResource.

CSRF protection (the OAuth state parameter) is generated, stored and verified for you on every round trip.

It currently supports the following providers:

ProviderIdentifier ($provider)
Facebookfacebook
Gitlabgitlab
Githubgithub
Googlegoogle
Instagraminstagram
Linkedinlinkedin

Installation​

To install this package, you must use composer. We recommend installing it globally.

composer require bowphp/soauth

Configuration​

After installation, in your .env.json file, you must define the provider access credentials as follows:

Facebook configuration​

You can create a new Facebook application at https://developers.facebook.com/fr.

{
"FACEBOOK_CLIENT_ID": "client_id",
"FACEBOOK_CLIENT_SECRET": "client_secret",
"FACEBOOK_REDIRECT_URI": "redirect_uri"
}

Gitlab configuration​

{
"GITLAB_CLIENT_ID": "client_id",
"GITLAB_CLIENT_SECRET": "client_secret",
"GITLAB_REDIRECT_URI": "redirect_uri"
}

GitHub configuration​

{
"GITHUB_CLIENT_ID": "client_id",
"GITHUB_CLIENT_SECRET": "client_secret",
"GITHUB_REDIRECT_URI": "redirect_uri"
}

Google configuration​

{
"GOOGLE_CLIENT_ID": "client_id",
"GOOGLE_CLIENT_SECRET": "client_secret",
"GOOGLE_REDIRECT_URI": "redirect_uri"
}

Instagram configuration​

{
"INSTAGRAM_CLIENT_ID": "client_id",
"INSTAGRAM_CLIENT_SECRET": "client_secret",
"INSTAGRAM_REDIRECT_URI": "redirect_uri"
}

LinkedIn configuration​

{
"LINKEDIN_CLIENT_ID": "client_id",
"LINKEDIN_CLIENT_SECRET": "client_secret",
"LINKEDIN_REDIRECT_URI": "redirect_uri"
}
Note

The configuration always follows the same approach: three keys <PROVIDER>_CLIENT_ID, <PROVIDER>_CLIENT_SECRET, <PROVIDER>_REDIRECT_URI.

The redirect_uri you set here must exactly match the callback route you register in your application (see Adding a route) and the one declared in the provider's developer console β€” otherwise the provider will reject the request.

These environment values are read by the package's config/soauth.php, which maps each provider name to its credentials. Your own config/soauth.php, if present, is merged on top of the defaults, so you can override any value locally.

Facebook Graph API version​

The Facebook provider talks to a specific Graph API version (v18.0 by default). To pin a different version, override the graph_api_version key in your config/soauth.php:

config/soauth.php
return [
'facebook' => [
'client_id' => app_env('FACEBOOK_CLIENT_ID'),
'client_secret' => app_env('FACEBOOK_CLIENT_SECRET'),
'redirect_uri' => app_env('FACEBOOK_REDIRECT_URI'),
'graph_api_version' => 'v19.0',
],
];

Usage​

Enable the package by adding it to Kernel::configurations():

app/Kernel.php
public function configurations(): array
{
return [
\Bow\Soauth\SoauthConfiguration::class,
// ... other providers
];
}

The package exposes a single, static entry point β€” Bow\Soauth\Soauth β€” with two methods:

  • Soauth::redirect(string $provider, array $scope = []) β€” send the user to the provider's consent screen.
  • Soauth::resource(string $provider) β€” handle the callback and return the authenticated UserResource.

Consider the following controller:

namespace App\Controllers;

use App\Controllers\Controller;
use Bow\Soauth\Soauth;

class SoauthController extends Controller
{
/**
* Redirect to the defined provider
*
* @param string $provider
* @return mixed
*/
public function redirect(string $provider)
{
// The second argument $scope is optional: pass an array of
// OAuth permissions (e.g. ['email', 'public_profile']) or omit it
// to use the provider's default scope.
return Soauth::redirect($provider, ['email']);
}

/**
* Handle the return from the OAuth provider
*
* @param string $provider
* @return mixed
*/
public function handle(string $provider)
{
$user = Soauth::resource($provider);

// Log the user in or create them, then redirect:
session()->add('user', $user->toArray());

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

The $provider value comes from the route and must match one of the supported providers: facebook, gitlab, github, google, instagram, or linkedin. An unknown or unconfigured name throws a Bow\Soauth\Exception\SoauthException.

Scopes​

The second argument to Soauth::redirect() is the list of OAuth permissions ("scopes") you are asking the user to grant. Scopes are provider-specific, so request only what you need:

// Ask Facebook for the email and the public profile
return Soauth::redirect('facebook', ['email', 'public_profile']);

// Ask GitHub for the user's email addresses
return Soauth::redirect('github', ['user:email']);

Omit the argument entirely to fall back to the provider's default scope:

return Soauth::redirect('google');

Adding a route​

Define the routes that will be used for the Soauth callback actions:

routes/app.php
$app->get('/oauth/:provider/redirect', 'SoauthController::redirect');
$app->get('/oauth/:provider/callback', 'SoauthController::handle');

The :provider segment becomes the $provider argument passed to your controller methods. The /callback route must match the redirect_uri configured for the provider.

Retrieving the user​

Soauth::resource() returns a Bow\Soauth\UserResource instance. It normalises the data returned by the different providers behind a consistent set of getters, so your code does not have to branch per provider:

$user = Soauth::resource($provider);

$user->getId(); // provider user id (string)
$user->getName(); // full name
$user->getNickName(); // username / nickname
$user->getFirstName(); // first name
$user->getLastName(); // last name
$user->getEmail(); // email address
$user->getPictureUrl(); // avatar URL (normalised across providers)
$user->getGender(); // gender
$user->getLink(); // profile URL
$user->getHometown(); // location (array)

Every getter returns null when the provider did not supply that field (for example, when the matching scope was not requested), so always guard the value before using it.

To work with the raw payload, use toArray() to get the full provider response or getAttribute() to read a single key:

$all = $user->toArray();             // full normalised array
$verified = $user->getAttribute('verified_email'); // any provider-specific key
Note

Some UserResource getters β€” getBio(), getCoverPhotoUrl(), getLocale(), and getTimezone() β€” map to fields that providers have deprecated or removed, and will usually return null. Prefer the actively supported getters above.

Error handling​

The package throws Bow\Soauth\Exception\SoauthException in the following cases:

  • the requested $provider name is unknown;
  • the provider is not configured (missing credentials block);
  • the OAuth state is missing, expired or does not match (a possible CSRF attempt, or the user landed on the callback without going through redirect() first);
  • the authorization code is absent from the callback request.

Wrap the callback handling to fail gracefully:

use Bow\Soauth\Soauth;
use Bow\Soauth\Exception\SoauthException;

public function handle(string $provider)
{
try {
$user = Soauth::resource($provider);
} catch (SoauthException $e) {
return redirect('/login')->withFlash('error', 'Authentication failed.');
}

session()->add('user', $user->toArray());

return redirect('/dashboard');
}

Is something missing?

If you run into problems with the documentation or have suggestions to improve the documentation or the project in general, please open an issue for us, or send a tweet mentioning the Twitter account @bowframework or directly on github.