This solution uses a dual-mode approach—silent login plus authorized login—to solve two problems in WeChat Mini Programs: frictionless sign-in for returning users and compliant registration for new users. The core mechanism relies on request interceptors and route guards to trigger the login flow, uses
is_new_userto distinguish new and returning users, and closes the loop through authorization-based profile completion. Keywords: WeChat Mini Program, silent login, uni-app.
This login architecture balances user experience and compliance
| Parameter | Description |
|---|---|
| Language | JavaScript, Vue, uni-app |
| Runtime Platforms | WeChat Mini Program, H5 (compatibility branch) |
| License | No open-source license is declared in the article; the repost license is CC 4.0 BY-SA |
| Stars | Not provided in the original source |
| Core Dependencies | uni.login, uni.getUserProfile, Vuex, request interceptors, route guards |
The core of this solution is not simply creating two login buttons. Instead, it splits login into two clearly defined paths.
Returning users follow the silent login path, whose goal is to reduce interruptions. New users follow the authorized login path, whose goal is to obtain the avatar, nickname, and complete registration in a way that satisfies platform privacy compliance requirements.
A dual-mode strategy is more reliable than a single login flow
If you implement only silent login, you cannot legally obtain profile information from new users. If you implement only authorized login, returning users must click manually every time they enter, which hurts both conversion and retention.
The dual-mode strategy has only one critical decision point: the backend returns is_new_user. That field determines whether the frontend should log the user in directly or move them into the authorization and profile-completion flow.
// Core branch logic for new and returning users
if (loginData.token && !loginData.is_new_user) {
store.commit('login', loginData); // Returning user: log in directly
} else {
// New user: stay unauthenticated and wait for the authorization flow
}
This logic makes both a frictionless experience and authorization compliance possible at the same time.
Silent login should be triggered by interceptors instead of running at startup
In the original implementation, silent login is not executed directly in App.vue onLaunch. Instead, it is attached to the recovery path after a failed request. This design is more production-friendly.
When any API returns code = -1, it indicates that the token is invalid or the user is not logged in. After the response interceptor receives this signal, it calls toLogin() centrally and then enters mnpLogin() based on the current platform.
The request interceptor is the primary trigger
// utils/request.js
const events = {
redirect({ msg }) {
if (store.getters.appConfig.mnp_status) {
toLogin(); // Trigger silent login after token expiration
}
store.commit('logout'); // Clear local state
return Promise.reject(msg);
}
};
service.interceptors.response.use((response) => {
const { code } = response.data;
return events[APICodeEnum[code]](response.data); // code=-1 -> redirect
});
Its main value is that login recovery is consolidated at the network layer instead of being scattered across pages.
The route guard provides a fallback for protected pages
When a user accesses a page with meta.auth = true, the route guard blocks navigation and redirects the user to the login page even if no API request has been sent yet.
// router.js
router.beforeEach((to, from, next) => {
if (to.meta.auth && !store.getters.token) {
next('/pages/login/login'); // Intercept all pages that require login
return;
}
next();
});
This ensures that both API access scenarios and page navigation scenarios are covered by login control.
The core value of silent login is that it serves only returning users
The silent login flow is short: call uni.login() to get a code, call login/silentLogin, and let the backend exchange the code for an openid. It then checks whether that openid exists in the database and returns the corresponding user state.
What matters most is not the API call itself, but the frontend constraint on the response: even if a new user receives a token, the app should not complete login immediately.
mnpLogin should be controlled by throttling and configuration
// utils/login.js
export const toLogin = trottle(_toLogin, 2000); // Throttle for 2 seconds to avoid repeated triggers
export async function mnpLogin() {
const { coerce_mobile, mnp_auto_wechat_auth } = store.getters.appConfig;
if (!mnp_auto_wechat_auth) return; // Exit directly if automatic silent login is disabled
const code = await getCode(); // Get the WeChat login credential
const loginData = await apiSilentLogin({ code });
if (coerce_mobile && !loginData.mobile) return; // Stop here if phone binding is mandatory
if (loginData.token && !loginData.is_new_user) {
store.commit('login', loginData); // Only returning users enter the formal logged-in state
store.dispatch('getUser');
store.dispatch('getCartNum');
}
}
This code reflects three layers of control: platform configuration, trigger throttling, and user-type branching.
Authorized login is responsible for completing registration and profile completion
Authorized login should only be triggered by explicit user action, such as clicking a one-tap login button. This is the only way to satisfy explicit-consent requirements in both interaction design and auditability.
The flow first checks whether the user has accepted the agreement, then calls uni.getUserProfile() to get the avatar and nickname, then uses uni.login() to get a code and requests login/authLogin.
Authorized login is both a login flow and a registration entry point
// pages/login/login.vue
async mnpLogin() {
if (!this.isAgree) {
this.showModel = true; // Block the flow until the agreement is accepted
return;
}
const { userInfo: { avatarUrl, nickName } } = await getUserProfile();
const code = await getCode();
const data = await apiAuthLogin({
code,
nickname: nickName,
headimgurl: avatarUrl
});
if (data.is_new_user) {
this.showLoginPop = true; // New user: show the profile-completion modal
this.loginData = data;
} else {
this.loginHandle(data); // Returning user: complete login directly
}
}
This combines “retrieving public profile information” and “creating a business account” into one explicit user action.
Profile completion is the last mile for new users
After authLogin creates an account for a new user, the system may still require additional information such as nickname, avatar, or mobile number. A modal provides a smoother experience than forcing a full-page redirect.
// New user submits additional profile information
async handleSubmitInfo(formData) {
await apiUpdateUser(formData, this.loginData.token); // Update the profile with a temporary token
this.loginHandle(this.loginData); // Enter the formal logged-in state after the update completes
}
This step separates “registration success” from “profile completeness,” which lowers the entry barrier during the first visit.
Backend API design must standardize its semantics around is_new_user
The frontend can be complex, but the shared fields between frontend and backend should be few and stable. The three most critical fields here are is_new_user, token, and mobile.
login/silentLogin identifies the user state and should not force completion of login for new users. login/authLogin handles registration or login after explicit authorization. login/updateUser handles profile completion.
The recommended response structure should stay consistent
{
"token": "eyJ0eXAiOiJKV1Qi...",
"is_new_user": false,
"mobile": "13800138000"
}
A unified response structure significantly reduces frontend branching complexity and debugging costs.
Configuration coordination is the most commonly overlooked implementation detail
Configuration is not an accessory. It is the control panel for the entire flow. mnp_auto_wechat_auth determines whether automatic silent login is enabled. mnp_wechat_auth determines whether the authorization button is displayed. coerce_mobile determines whether mobile number binding is required.
If these three switches do not align with frontend logic and backend responses, you will see issues such as returning users not signing in automatically, new users being unable to register, or repeated redirects to the login page.
The minimum integration checklist is as follows
utils/login.js: encapsulategetCode,toLogin, andmnpLoginutils/request.js: handlecode = -1in the response interceptorrouter.js: intercept pages withmeta.authapi/app.js: definesilentLogin,authLogin, andupdateUserpages/login/login.vue: implement the authorized login and profile-completion flowstore/index.js: manage shared state such as token, user information, and cart data
The image data in the original source is primarily decorative site branding

This image is the brand mark for the CSDN AI reading assistant. It is a logo/branding element, so no additional visual technical analysis is needed.
The engineering conclusion of this solution is straightforward
Silent login does not replace authorized login. It exists to reduce friction for returning users. Authorized login does not add unnecessary steps. It exists to make new-user registration compliant and ensure profile completeness.
From a system design perspective, the best practice is clear: let the network layer trigger silent recovery, let the routing layer handle access interception, let the page layer handle user authorization, and let the backend use is_new_user as the unified decision signal. That is how you turn login into maintainable infrastructure instead of temporary page-level logic.
FAQ
FAQ 1: Why can’t a new user log in directly after silent login returns a token?
Answer: Because silent login does not include explicit user consent to access information such as avatar and nickname. A new user must complete the authorized login flow before the app can finish compliant registration and profile completion.
FAQ 2: Why is it recommended to attach silent login to the request interceptor?
Answer: Because token expiration first appears in API responses. Putting recovery logic in the interceptor gives you a centralized way to handle both unauthenticated and expired-token states, instead of duplicating login branches across pages.
FAQ 3: What is the most important backend response field?
Answer: It is is_new_user. This field directly determines whether the frontend automatically logs in a returning user or guides a new user into the authorization and profile-completion flow. It is the central signal in the entire dual-mode design.
Core Summary
This article reconstructs a dual-mode WeChat Mini Program login solution based on silent login and authorized login. It focuses on how request interceptors trigger silent login, how route guards provide fallback redirects, how is_new_user distinguishes new and returning users, and how authorized login completes registration and profile completion. It is well suited for implementing a uni-app Mini Program login system.