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:
- Your app redirects the user to the provider's consent screen.
- The user approves, and the provider calls back to your app with a code.
- 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:
| Provider | Identifier ($provider) |
|---|---|
facebook | |
| Gitlab | gitlab |
| Github | github |
google | |
instagram | |
linkedin |
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"
}
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:
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():
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 authenticatedUserResource.
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');
}
}
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:
$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
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
$providername is unknown; - the provider is not configured (missing credentials block);
- the OAuth
stateis missing, expired or does not match (a possible CSRF attempt, or the user landed on the callback without going throughredirect()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.