socialiteproviders/wechat-service-account
This Laravel Socialite provider adds WeChat Service Account (Official Account) OAuth login to your app. Configure your WeChat App ID and secret, then authenticate users through the standard Socialite driver—ideal for Chinese-market apps that need WeChat sign-in.
Install the provider alongside the SocialiteProviders manager:
composer require socialiteproviders/wechat-service-account
Add credentials to config/services.php. The key must match the driver name you'll pass to Socialite::driver():
'wechat_service_account' => [
'client_id' => env('WECHAT_SERVICE_ACCOUNT_APP_ID'),
'client_secret' => env('WECHAT_SERVICE_ACCOUNT_APP_SECRET'),
'redirect' => env('WECHAT_SERVICE_ACCOUNT_REDIRECT_URI'),
],
Then register the SocialiteWasCalled listener. Without this step Laravel throws Driver [wechat_service_account] is not supported:
// Laravel < 11: app/Providers/EventServiceProvider.php
protected $listen = [
\SocialiteProviders\Manager\SocialiteWasCalled::class => [
\SocialiteProviders\WeChatServiceAccount\WeChatServiceAccountExtendSocialite::class,
],
];
// Laravel 11+: AppServiceProvider::boot() or bootstrap/app.php's withEvents
Event::listen(
\SocialiteProviders\Manager\SocialiteWasCalled::class,
\SocialiteProviders\WeChatServiceAccount\WeChatServiceAccountExtendSocialite::class
);
First use case — the canonical redirect/callback pair:
Route::get('/auth/wechat', fn () => Socialite::driver('wechat_service_account')->redirect());
Route::get('/auth/wechat/callback', function () {
$wechatUser = Socialite::driver('wechat_service_account')->user();
// ->getId() => openid
// ->getNickname(), ->getAvatar(), ->getRaw() (contains unionid, headimgurl, privilege…)
});
Where to look first:
src/WeChatServiceAccountProvider.php — read getAuthUrl(), getTokenUrl(), getUserByToken() and mapUserToObject(). This tells you what scope is sent by default (snsapi_base vs snsapi_userinfo) and which user fields are mapped onto Socialite's contract.composer.json — check the pinned laravel/socialite / socialiteproviders/manager constraints. The last release is from December 2020, so the supported Socialite major matters.Two scopes, two workflows. WeChat official account OAuth supports snsapi_base (silent, returns only openid) and snsapi_userinfo (consent prompt, returns nickname, headimgurl, unionid). Check getAuthUrl() for the default the package sends; override via ->with(['scope' => 'snsapi_userinfo']) if it's not hardcoded. Use snsapi_base for "who is this already-following user" inside the account, and snsapi_userinfo for onboarding/profile prefill.
Account binding table. Don't put openid on users. Create a social_accounts table keyed by (provider, provider_id) with an optional unionid column. On callback: look up the account, log the user in if found, otherwise show a bind/register screen and attach the account on completion. This keeps multiple providers and multiple app contexts clean.
Treat unionid as canonical, openid as per-app. openid is scoped to a single WeChat app; unionid (only returned when the official account is bound to WeChat Open Platform) is stable across service account, mini program, and Open Platform web login. If you support more than one WeChat surface, join on unionid and keep openid as an attribute.
Pair with another provider for non-WeChat browsers. This package implements the official-account web flow, which only completes inside WeChat's in-app browser. For desktop QR login, use the Open Platform / WeChat Web provider from the same SocialiteProviders family and reconcile identities on unionid.
Persist the token response, not just the user. Call ->getRaw() (and inspect ->getToken() / the token response) and store openid, unionid, nickname, headimgurl, privilege, plus the user access_token and refresh_token if you plan to call WeChat APIs later. Refresh tokens here are WeChat-specific — renew via sns/oauth2/refresh_token, not a standard OAuth refresh endpoint.
Wrap the driver. A small service class around Socialite::driver('wechat_service_account') lets you swap in a fork, a newer Socialite version, or the Open Platform provider without touching controllers.
Stateless usage is possible but rarely worth it. ->stateless()->user() works, but for browser redirects inside WeChat, keep the default state validation; CSRF protection across the redirect round-trip is cheap.
Socialite::driver() throws "not supported," 9 times out of 10 the SocialiteWasCalled listener isn't wired. In Laravel 11+ there's no default EventServiceProvider — register explicitly.wechat_service_account. A typo produces a confusing Undefined array key during provider construction rather than a friendly error.code, expired token, or wrong secret comes back as JSON with errcode / errmsg. Common codes: 40029 invalid code, 40163 code already used, 40013 invalid appid, 40125 invalid secret, 41008 missing code. The package may not surface these — log getRaw() and check for errcode.#wechat_redirect. If your HTTP client, reverse proxy, or framework strips fragments from redirects, users hit a broken consent page. Don't rebuild the URL manually; let getAuthUrl() do it.redirect_uri errors on WeChat's side, not in Laravel.MicroMessenger in the user agent and offer an alternative (QR login via the Open Platform provider).snsapi_base gives you nothing but openid. No nickname, no avatar. If you need profile data, request snsapi_userinfo and accept the user-facing consent screen — there's no way around it.getEmail() is null; WeChat official accounts do not expose email. Plan your user model and any "password reset"-style flows accordingly.laravel/socialite major (v4 vs v5/v6) before committing. Budget for either pinning Socialite or forking the provider — the file is small enough that a fork is usually a day's work, not a week's.WeChatServiceAccountProvider and register it via Socialite::extend() / a custom SocialiteWasCalled listener when you need a different default scope, extra query params (lang, connect_redirect), or to normalize getEmail() / getId() onto your domain model.code and state query params intact.How can I help you explore Laravel packages today?