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

Weixin Web Laravel Package

socialiteproviders/weixin-web

Add WeChat (Weixin) web login to Laravel Socialite with this provider from SocialiteProviders. It implements WeChat Open Platform QR-code OAuth authorization, letting users sign in to your Laravel app by scanning a code, with a simple driver you register in Socialite.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Install the package (and the manager it depends on).

composer require socialiteproviders/weixin-web socialiteproviders/manager

Pin to the PHP 8 line if you're on a modern stack:

composer require "socialiteproviders/weixin-web:^4.1"

2. Register the provider listener. In app/Providers/EventServiceProvider.php (Laravel ≤10):

protected $listen = [
    \SocialiteProviders\Manager\SocialiteWasCalled::class => [
        \SocialiteProviders\WeixinWeb\WeixinWebExtendSocialite::class.'@handle',
    ],
];

On Laravel 11+ (no default EventServiceProvider), put the same Event::listen(...) call in AppServiceProvider::boot().

3. Add credentials to config/services.php. The config key must match the driver name you pass to Socialite::driver(). For this package that is weixinweb (verify against WeixinWebExtendSocialite in vendor/ — the extend() key is the driver name):

'weixinweb' => [
    'client_id'     => env('WEIXINWEB_CLIENT_ID'),
    'client_secret' => env('WEIXINWEB_CLIENT_SECRET'),
    'redirect'      => env('WEIXINWEB_REDIRECT_URI'), // must be registered in WeChat Open Platform
],

4. First use case — QR-code login for desktop web. Two routes and a controller is the whole integration:

// routes/web.php
Route::get('/auth/wechat', [WeChatAuthController::class, 'redirect'])->name('wechat.redirect');
Route::get('/auth/wechat/callback', [WeChatAuthController::class, 'callback'])->name('wechat.callback');
class WeChatAuthController extends Controller
{
    public function redirect()
    {
        return Socialite::driver('weixinweb')->redirect();
    }

    public function callback()
    {
        $wxUser = Socialite::driver('weixinweb')->user();

        $user = User::firstOrCreate(
            ['weixin_openid' => $wxUser->getId()],
            [
                'name'          => $wxUser->getNickname() ?: 'WeChat User',
                'avatar'        => $wxUser->getAvatar(),
                'weixin_unionid'=> $wxUser->getRaw()['unionid'] ?? null,
            ]
        );

        Auth::login($user);

        return redirect()->intended('/dashboard');
    }
}

Where to look first when something is wrong: vendor/socialiteproviders/weixin-web/src/Provider.php. It's small — it documents the exact driver key, the scope it sends (snsapi_login), and how raw WeChat fields are mapped onto Socialite's User. That file is your source of truth for config keys and field names, because the package has had no release since 2020-12-01 (4.1.0, the PHP 8 bump) and its README is thin.


Implementation Patterns

Standard redirect/callback (server-rendered apps)

The default flow above is the cleanest and works for most Laravel apps. Keep the redirect URI on a route that requires no auth, and Auth::login() in the callback. Store the Socialite user only after you resolve it to your own User model — don't leak the Socialite user object into the session.

Embedded QR without a full-page redirect

WeChat's web login is a QR scan; many teams embed the QR inside an existing login modal instead of bouncing the user away. You lose nothing by building the URL yourself and reusing the same callback:

$params = http_build_query([
    'appid'         => config('services.weixinweb.client_id'),
    'redirect_uri'  => urlencode(route('wechat.callback')),
    'response_type' => 'code',
    'scope'         => 'snsapi_login',
    'state'         => csrf_token(),
]);
$qrUrl = "https://open.weixin.qq.com/connect/qrconnect?{$params}#wechat_redirect";

Pass $qrUrl to the view and render it in an iframe (<iframe src="{{ $qrUrl }}">) or via the WeChat JS SDK. Because you now own the state, validate it on the callback yourself.

Stateless flow for SPAs / mobile WebViews

If the browser session isn't available on the callback (API token auth, separate SPA origin), use:

return Socialite::driver('weixinweb')->stateless()->redirect();
// callback
$wxUser = Socialite::driver('weixinweb')->stateless()->user();

You then own state/CSRF entirely (put a signed nonce in the OAuth state and verify it on return). Don't mix stateless and session flows on the same route — you'll get silent InvalidStateExceptions.

Identity: openid vs unionid

  • getId() returns the openid, which is scoped to this specific app. Fine if WeChat web is your only WeChat entry point.
  • If you also have a mini program, mobile app, or official account under the same WeChat Open Platform developer account, capture unionid from $wxUser->getRaw()['unionid'] and key accounts on it. It's the only stable cross-app identifier.
  • Guard for unionid being absent: WeChat only returns it when the app is bound to the Open Platform account and the user relationship qualifies. Store it nullable.

Account linking for existing users

A common day-to-day pattern is letting an already-logged-in user attach WeChat:

$wxUser = Socialite::driver('weixinweb')->user();
if (Auth::check()) {
    Auth::user()->update(['weixin_openid' => $wxUser->getId()]);
} else {
    // find-or-create, or prompt to link
}

Uniqueness constraints: put a unique index on weixin_openid and weixin_unionid (nullable), and catch the resulting QueryException to recover from double-submits.

Profile refresh on demand

The login exchange calls sns/userinfo each time. If you need fresh profile data later (nickname/avatar changes), don't re-run OAuth — cache the profile at login and treat WeChat's data as best-effort. WeChat does not guarantee current, complete profile data.

Testing

Socialite is mockable, so your controller test shouldn't hit WeChat:

Socialite::shouldReceive('driver->user')->andReturn(
    (new \Laravel\Socialite\Two\User)->map([
        'id' => 'openid-123', 'nickname' => 'tester', 'avatar' => 'https://…',
    ])
);

For an end-to-end check, exercise Provider::user() against a fixture response — the mapping logic is the only real risk, and it's small.

Composing with other providers

If WeChat is one of several Socialite drivers (Google, GitHub, etc.), keep one SocialAuthController that switches on $provider and one config/services.php block per provider. This package slots in exactly like the others because it implements the same Two\Provider contract.


Gotchas and Tips

Configuration and setup

  • Driver name mismatch is the #1 silent failure. Socialite::driver('weixinweb') reads config('services.weixinweb') and resolves the extend key registered by the package. If you used a different key (e.g. weixin), the manager throws "Driver not supported" or uses the wrong credentials. Confirm both against the package source.
  • Run php artisan config:cache after editing .env. The credentials are read through config(), so a stale cache is easy to mistake for a bad App Secret.
  • The redirect URI must match exactly, including scheme, host, path, and trailing slash, and the domain must be registered on the WeChat Open Platform website app. Wildcards and localhost are not accepted in production. For local dev, tunnel a public HTTPS URL (ngrok/Cloudflare) and register that domain.
  • The app must be a Website App (网站应用) under 开放平台 — an Official Account (公众号) app will not work with this provider/scope.

OAuth/API behaviour you'll hit

  • snsapi_login is hardcoded for the web QR flow. Don't change it to snsapi_userinfo — that belongs to the official-account package (socialiteproviders/wechat). Mixing scopes produces invalid scope (10003 / 40029-class errors).
  • Codes are single-use and short-lived (~5 minutes). A retry, double-click, or browser refresh on the callback means 40163 ("code been used") or 40029 ("invalid code"). Redirect the user back to /auth/wechat on those errors rather than surfacing them.
  • No email. WeChat has no email field; getEmail() will be null. Design your user table so email is nullable or prompt for it after registration.
  • Nicknames can contain emoji and unusual Unicode. Use utf8mb4 and utf8mb4_unicode_ci on the relevant columns, otherwise firstOrCreate blows up on insertion.
  • headimgurl is unreliable — sometimes blank, sometimes http://, sometimes a default. Validate before persisting and fall back to a local placeholder.
  • getRaw() is your escape hatch for unionid, province, city, country, sex, and any WeChat error payload. Always null-coalesce; keys vary by user and authorization state.
  • Wrap user() in try/catch. Token-exchange failures throw \Laravel\Socialite\Two\InvalidStateException or a generic ClientException; catch both and return a friendly message with a "Try again" link back to /auth/wechat.

Maintenance and compatibility risks

  • This package has had no release since 2020-12-01. 4.1.0 only added PHP 8 support. It's a thin wrapper, so it usually keeps working, but pin it (^4.1) and run the full suite on your PHP version. Use composer why-not socialiteproviders/weixin-web when a Laravel/Socialite bump complains.
  • Watch the Laravel Socialite major version. Major Socialite changes (user object internals, Two\AbstractProvider contract) could break this package first, since it's unmaintained. Add a focused test around Provider::user() so an upgrade fails loudly.
  • PHP 8 minor behavior differs (8.0 vs 8.1 vs 8.2 deprecations). Test on the exact version you deploy, not just "PHP 8".
  • Fork it if you need to move fast. The provider is a few hundred lines; if a Socialite upgrade breaks it, patching your fork is faster than waiting on a release that may never come.

Debugging checklist

  1. Confirm driver name and config key match (config('services.weixinweb') is populated).
  2. Confirm WEIXINWEB_REDIRECT_URI byte-for-byte matches what's registered in WeChat Open Platform.
  3. Hit /auth/wechat directly — if you don't land on open.weixin.qq.com/connect/qrconnect, the driver isn't resolving.
  4. If the QR page loads but you get an error, read the error/errcode query params (40029, 40163, 10003, 40013 for bad AppID).
  5. Log $wxUser->getRaw() on the callback to see the exact payload WeChat returned before your mapping runs.
  6. If the callback hangs or throws "Invalid state", verify the session cookie survives the round trip to WeChat and back (SameSite/Secure settings, or switch to stateless()).
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.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib