-
Notifications
You must be signed in to change notification settings - Fork 2
SocialAuth
Pair\Services\SocialAuth is Pair's lightweight OAuth/OIDC helper for social sign-in flows.
It builds provider authorization URLs, stores single-use callback state in the native PHP session, exchanges authorization codes for tokens, and normalizes provider profiles into one stable object shape.
Pair ships built-in metadata for:
- Apple
- Microsoft
- WhatsApp / Facebook OAuth
Custom providers can be passed directly to the constructor when they expose compatible OAuth authorization, token, and profile endpoints.
Enable the providers that should be available in UI:
PAIR_SOCIAL_AUTH_PROVIDERS=google,apple,microsoft,whatsapp
PAIR_SOCIAL_AUTH_TIMEOUT=15
PAIR_SOCIAL_AUTH_CONNECT_TIMEOUT=5Provider credentials use the PAIR_SOCIAL_<PROVIDER>_ prefix:
PAIR_SOCIAL_GOOGLE_CLIENT_ID=
PAIR_SOCIAL_GOOGLE_CLIENT_SECRET=
PAIR_SOCIAL_APPLE_CLIENT_ID=
PAIR_SOCIAL_APPLE_CLIENT_SECRET=
PAIR_SOCIAL_APPLE_TEAM_ID=
PAIR_SOCIAL_APPLE_KEY_ID=
PAIR_SOCIAL_APPLE_CLIENT_SECRET_TTL=
PAIR_SOCIAL_APPLE_PRIVATE_KEY=
PAIR_SOCIAL_APPLE_PRIVATE_KEY_PATH=
PAIR_SOCIAL_MICROSOFT_CLIENT_ID=
PAIR_SOCIAL_MICROSOFT_CLIENT_SECRET=
PAIR_SOCIAL_WHATSAPP_CLIENT_ID=
PAIR_SOCIAL_WHATSAPP_CLIENT_SECRET=
PAIR_SOCIAL_WHATSAPP_CONFIG_ID=Advanced provider overrides follow the same prefix:
LABELICONAUTHORIZE_URLTOKEN_URLPROFILE_URLSCOPESPROFILE_QUERYAUTHORIZE_PARAMS
SCOPES accepts comma-separated or space-separated values. PROFILE_QUERY and AUTHORIZE_PARAMS accept query-string syntax.
Builds the helper from explicit providers or from .env configuration.
When $providers is omitted, PAIR_SOCIAL_AUTH_PROVIDERS controls which built-in providers are loaded.
Returns UI-safe provider summaries:
use Pair\Services\SocialAuth;
$providers = (new SocialAuth())->providers();Each row contains:
keylabelicon
Checks whether a provider is configured and usable.
use Pair\Services\SocialAuth;
if ((new SocialAuth())->hasProvider('google')) {
// Render the Google sign-in button.
}Creates the authorization URL and stores the anti-forgery state in the native PHP session.
use Pair\Services\SocialAuth;
$auth = new SocialAuth();
$url = $auth->begin(
'google',
'https://app.example.test/auth/social/google/callback',
['flow' => 'login']
);
$this->redirect($url, externalUrl: true);$context is stored with the state and restored after callback completion. Use it for flow details such as login/register intent, tenant, or return URL.
Validates callback state, exchanges the authorization code, loads the profile, and returns a normalized object.
use Pair\Services\SocialAuth;
$auth = new SocialAuth();
$profile = $auth->complete(
'google',
$_GET,
'https://app.example.test/auth/social/google/callback'
);
$externalId = $profile->provider . ':' . $profile->subject;Returned fields include:
providerprovider_labelsubjectemailemail_verifiednamegiven_namefamily_nameavatar_urlraw_profiletokenstatecontext
Apple can return profile data through both id_token and the user form payload. SocialAuth merges both sources.
Apple's built-in provider metadata uses response_mode=form_post, so callback controllers should pass the posted payload to complete() for Apple routes and the query payload for standard redirect providers.
If PAIR_SOCIAL_APPLE_CLIENT_SECRET is empty, Pair can generate the Sign in with Apple client-secret JWT from:
PAIR_SOCIAL_APPLE_TEAM_IDPAIR_SOCIAL_APPLE_KEY_IDPAIR_SOCIAL_APPLE_CLIENT_SECRET_TTLPAIR_SOCIAL_APPLE_PRIVATE_KEYPAIR_SOCIAL_APPLE_PRIVATE_KEY_PATH
Applications may also provide the private key directly with PAIR_SOCIAL_APPLE_PRIVATE_KEY, even though the default .env template prefers a file path.
- State values are random, stored server-side, and single-use.
- Stored state expires after 10 minutes.
-
complete()can enforce the exact redirect URI used bybegin(). - Provider HTTP errors are converted to
PairExceptionwithErrorCodes::SOCIAL_AUTH_ERROR. - ID token payloads are decoded only for profile claims; they are not treated as proof of authorization by themselves.
use Pair\Http\JsonResponse;
use Pair\Services\SocialAuth;
use Pair\Web\Controller;
final class SocialController extends Controller {
/**
* Redirect the browser to the selected social provider.
*/
public function loginAction(): void {
$provider = (string)$this->input()->string('provider');
$redirectUri = BASE_HREF . 'social/callback/' . $provider;
$url = (new SocialAuth())->begin($provider, $redirectUri, [
'flow' => 'login',
]);
$this->redirect($url, externalUrl: true);
}
/**
* Complete the provider callback and map the profile to an application user.
*/
public function callbackAction(): JsonResponse {
$provider = (string)$this->input()->string('provider');
$redirectUri = BASE_HREF . 'social/callback/' . $provider;
$profile = (new SocialAuth())->complete($provider, $_GET, $redirectUri);
return $this->json([
'provider' => $profile->provider,
'subject' => $profile->subject,
'email' => $profile->email,
]);
}
}See also: User, Session, Configuration-file, ErrorCodes, Integrations.