How to Implement Seamless, Secure Login in WeChat Mini‑Programs

This article explains why user authentication is essential for mobile mini‑programs, outlines security measures using AccessToken and RefreshToken, and provides step‑by‑step techniques—including automatic login, token refresh, request queuing, and user‑state handling—to achieve a frictionless user experience.

Goodme Frontend Team
Goodme Frontend Team
Goodme Frontend Team
How to Implement Seamless, Secure Login in WeChat Mini‑Programs

Preface

In the mobile Internet era, mobile apps are crucial as a bridge between users and services. Mini‑programs, with their lightweight, convenient, and fast‑startup characteristics, are gradually replacing traditional apps. User authentication is the foundation for all subsequent operations.

User Login Necessity

Security: only authenticated users can access their data.

Personalized customization: push content tailored to specific user behavior.

Cross‑device sync: identify users across devices via unique identifiers such as phone number, WeChat OpenId, etc.

Data analysis: collect behavior data to evaluate product impact and guide improvements.

Social interaction: enable user‑to‑user interaction and increase product reach.

How to Ensure Security

We use AccessToken and RefreshToken for API authentication. AccessToken has a short lifespan to prevent theft, but short life leads to frequent expiration, so RefreshToken is used to obtain a new AccessToken with a longer validity.

Authentication Flow

User Experience Focus

In mini‑programs the only identifier is WeChat, which yields UnionId and OpenId. The optimal experience is “no‑feeling” login. If the product needs a phone number, the user must authorize the binding because platforms tightly control phone number access.

How to Improve User Experience

Now we discuss how to achieve seamless login.

Problems to Solve

Automatic login

Refresh token when authentication fails

Continue user actions after token refresh

Idea

Obtain code via platform API, exchange for UnionId/OpenId on server, then register/login the user.

If API authentication fails, call refreshToken or trigger automatic login again.

Intercept 401 errors with the request library, wait for token reset, then retry the intercepted request.

Solution

Examples are based on WeChat; other platforms are similar.

Automatic Login

wx.login(Object object) | WeChat documentation
const login = async () => {
  const { code, errMsg } = await wx.login();
  // Call backend to exchange code for user identifier and obtain user info
  const user = await loginFunc(code);
}

Automatic Token Refresh

Determine when token refresh is not needed in request error interceptor

Non‑401 interface errors

User has logged out voluntarily

Special business‑defined scenarios

Reset User Information

refreshToken

Silent login

Retry Interface

Update token

Retry the 401‑blocked request

/*** Match status code */
const matchStatusCode = (response, statusCode) => {
  return [response.status, response.data.code].includes(statusCode);
};

/*** Determine whether to retry request */
const whetherToRetry = async (error, updateConfig) => {
  const { user } = rootStore;
  if (
    !matchStatusCode(error?.response, 401) ||
    user.isLogout ||
    error?.config?.meta?.reTry === false
  )
    return false;
  await resetUser();
  if (!user.token) return false;
  updateConfig({
    headers: {
      Authorization: `Bearer ${user.token}`,
    },
  });
  return true;
};

/*** Reset user */
const resetUser = async () => {
  const { user, common } = rootStore;
  if (user.isLogin) {
    await user.refreshToken();
  } else {
    await silentLogin();
  }
};

Continue User Actions

To achieve a seamless experience, we need to preserve the user’s previous operations.

Use userInited to record user reset state.

Use requestQueue to store pending API requests.

After user reset, execute all queued requests.

/*** Reset user */
const resetUser = async () => {
  const { user, common } = rootStore;
  if (!user.userInited)
    return new Promise(resolve => {
      common.setRequestQueue([...common.requestQueue, resolve]);
    });
  user.setUserInited(false);
  if (user.isLogin) {
    await user.refreshToken();
  } else {
    await silentLogin();
  }
  user.setUserInited(true);
};
constructor() {
  reaction(
    () => this.userInited,
    (arg) => {
      if (arg) {
        const { common } = rootStore;
        common.requestQueue.forEach(item => item());
        common.setRequestQueue([]);
      }
    }
  );
}

Pre‑wait for User Info Completion

If user information is not yet initialized, place authenticated requests into a waiting queue to avoid unnecessary calls.

/*** Wait for user initialization */
const waitForUserInited = async () => {
  const { user, common } = rootStore;
  if (user.userInited) return Promise.resolve();
  // Not initialized, block request in queue
  return new Promise(resolve => {
    common.setRequestQueue([...common.requestQueue, resolve]);
  });
};

http.tap('request', async (config) => {
  const { user } = rootStore;
  // Authenticated interface
  if (!NO_AUTH_URL.includes(config.rawURL)) {
    await waitForUserInited();
    config.headers.Authorization = `Bearer ${rootStore.user.token}`;
  }
});

Summary

Security is the foundation of user login; optimizing experience on this basis is essential.

Reducing unnecessary user actions improves perception and product conversion.

When both AccessToken and RefreshToken expire, we perform silent login to obtain a new token; in mini‑programs we use code to get OpenId and link it to private‑domain member data.

frontendAuthenticationloginTokenWeChatmini-program
Goodme Frontend Team
Written by

Goodme Frontend Team

Regularly sharing the team's insights and expertise in the frontend field

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.