socialiteproviders/wechat-web
WeChat Web OAuth provider for Laravel Socialite, enabling "Sign in with WeChat" for websites. Adds WeChat as a Socialite driver with minimal setup so you can authenticate users and fetch their profile via the WeChat Open Platform.
Architecture fit. socialiteproviders/wechat-web is a Laravel Socialite driver, not a standalone SDK. It slots into an existing Socialite auth flow as one additional driver: one Composer package, one entry in config/services.php (client ID/secret/redirect), one SocialiteWasCalled listener registration, and a controller using Socialite::driver(...)->user(). It returns a Socialite-compatible User object and persists nothing — account mapping, session creation, and storage remain ours. That is a clean, low-coupling fit if Socialite is already the auth substrate. If it isn't, we are adopting Socialite plus socialiteproviders/manager to get one button.
The underlying flow is the WeChat Open Platform 网站应用 (website app) authorization-code flow with QR-code login: an outbound redirect to open.weixin.qq.com/connect/qrconnect, a callback carrying code, then server-side token and userinfo calls. Stateless, no webhooks, no daemons, no data residency surface beyond what we choose to store.
Integration feasibility. Engineering effort is genuinely small — roughly 1–2 days for a working, tested flow. The friction sits on both sides of the code:
illuminate/support and socialiteproviders/manager constraints almost certainly exclude Laravel 9/10/11 and PHP 8.1+. Expect composer require to fail on a modern app.Technical risk.
| Risk | Severity | Note |
|---|---|---|
| Abandoned/split-only package | High | READ ONLY subtree split; fixes must land in SocialiteProviders/Providers monorepo, where a patch may never arrive. We are de facto maintainers. |
| Framework version drift | High | Undeclared Laravel 10/11 and PHP 8.2/8.3 support; Socialite AbstractProvider signature changes can produce fatals. |
| WeChat error-as-HTTP-200 | Medium | Failures arrive as errcode/errmsg in a 200 body (40029 invalid code, 40163 code already used, 42001 token expired). Without explicit checks this yields null users rather than exceptions. |
openid vs unionid |
Medium | unionid is only present when the app is bound to the Open Platform account. Keying on openid silently fragments identities across web / 公众号 / mini-program channels. |
| QR-only flow | Medium | Product-level: inside WeChat's in-app browser a user cannot scan a QR code. wechat-web covers desktop and non-WeChat mobile browsers only; in-app traffic needs the 公众号 OAuth driver with snsapi_userinfo — a second provider, or a different chassis. |
| Compliance | Medium | Storing nickname/avatar/unionid is personal information under PIPL; consent copy, retention, and a privacy policy update are prerequisites. |
Key questions.
unionid for cross-channel account linking?Stack fit. Strong on Laravel 8 / PHP 7.3–8.0, which is the package's tested envelope. Below that, treat declared compatibility as unknown and prove it in a spike before committing.
Build vs. buy — four options, in preference order:
| Option | Effort | Verdict |
|---|---|---|
A. Custom provider (~150 LOC extending Socialite's AbstractProvider) |
1–2 days | Recommended. Full control of error handling, unionid mapping, and Laravel-version compatibility; no abandoned dependency to own anyway. |
B. overtrue/wechat (EasyWeChat) + Laravel bridge |
2–4 days | Recommended if WeChat is strategic (payments, 公众号, mini-program, JS-SDK). Actively maintained; the de facto standard in the Chinese PHP ecosystem. Heavier dependency. |
C. Fork wechat-web, widen constraints, host on internal VCS |
1 day + ongoing | Acceptable stopgap; you inherit maintenance without escaping it. |
| D. Install as-is with constraint overrides | Hours | Only for a throwaway spike. Do not ship. |
Migration path. No data migration is required by the package itself, but design for multi-channel identity from day one: a social_identities table (user_id, provider, provider_user_id, unionid nullable, unique on (provider, provider_user_id) and on unionid) rather than nullable columns on users. Keep password/phone login as a first-class fallback and add an explicit account-linking step for existing users, so a WeChat login never silently creates a duplicate account.
Compatibility and sequencing.
unionid-absent case).errcode handling, user-facing error states for scan-abandonment and expired codes, structured logging keyed on errcode.Maintenance. Effectively self-maintained: no release since 2020, community-only support routed to a monorepo we don't control. Budget ~2–4 engineer-days per year plus a patch at each Laravel major — and note that under option A that maintenance is ours by design, with the compensation of a smaller, fully understood surface.
Support. No vendor SLA. WeChat-side escalations go to Open Platform 客服: Chinese-language, business-hours, requires a verified account, and slow on domain/certification issues. Write an internal runbook covering credential rotation, callback-URL changes, and the "all logins failing" triage path.
Scaling. A non-issue. One authorization redirect and one outbound HTTPS call per login; ~50–150 ms from mainland China, ~200–400 ms elsewhere. Fully stateless and horizontally scalable. Because this flow uses per-user OAuth tokens rather than the global access_token, there is no shared-token quota bottleneck.
Failure modes to instrument and alert on:
errcode 40029 (invalid code) and 40163 (code already used — the classic double-submit/back-button case); these look like user error but often indicate a bug.unionid absent → duplicate accounts, discovered weeks later as inflated user counts.Ramp-up. Low: a Laravel developer familiar with Socialite is productive in half a day. The non-obvious parts are all WeChat-specific — error-as-200 semantics, openid vs unionid, and the in-app-browser/QR incompatibility. Front-load those in the spike; the second one especially, since it determines whether this package is a complete solution or one half of a two-driver product.
How can I help you explore Laravel packages today?