Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Wechat Service Account Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

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:

  1. 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.
  2. composer.json — check the pinned laravel/socialite / socialiteproviders/manager constraints. The last release is from December 2020, so the supported Socialite major matters.
  3. WeChat's official OAuth documentation (公众号网页授权) for the exact response shape and error codes — the package is a thin wrapper around it.

Implementation Patterns

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.

Gotchas and Tips

  • Listener registration is the #1 failure mode. If 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.
  • Config key must be wechat_service_account. A typo produces a confusing Undefined array key during provider construction rather than a friendly error.
  • WeChat returns errors with HTTP 200. A bad 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.
  • The auth URL ends in #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 must be registered and verified in the WeChat console. HTTPS required, domain whitelisted, and query strings/ports are finicky. A mismatch usually manifests as redirect_uri errors on WeChat's side, not in Laravel.
  • This flow only works inside WeChat's embedded browser. On desktop or external mobile browsers, the consent page cannot complete. Detect 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.
  • No email. getEmail() is null; WeChat official accounts do not expose email. Plan your user model and any "password reset"-style flows accordingly.
  • Codes are single-use and short-lived (~5 minutes). Don't retry the callback with the same code; guard against double-fired callbacks and back-button replays.
  • Stale package. Last release December 2020, 4 stars, 0 dependents. Verify it actually installs against your 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.
  • Extension points. Subclass 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.
  • Debugging checklist: confirm the listener is registered, log the raw token JSON, confirm the appid/secret pair matches the official account (not the Open Platform app), confirm the redirect domain is verified in the console, and confirm the callback arrives with code and state query params intact.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox