# How to Implement Two-Step Login Verification in Vue-Element-Admin

> Implement two-step login verification in vue-element-admin by extending the Vuex authentication module. Secure your application with enhanced login security.

- Repository: [花裤衩/vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)
- Tags: how-to-guide
- Published: 2026-02-27

---

**You can implement two-step login verification by extending the existing Vuex authentication module in [`src/store/modules/user.js`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/store/modules/user.js) to handle temporary tokens and adding a verification step in the login view component.**

Vue-Element-Admin provides a robust authentication system built on Vuex that handles JWT tokens through [`src/store/modules/user.js`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/store/modules/user.js). To add two-step login verification (2FA) to this existing architecture, you need to intercept the initial login response, store a temporary token when 2FA is required, and create a secondary verification action that exchanges the OTP code for the final authentication token.

## Understanding the Existing Authentication Flow

Before extending the system, you must understand how Vue-Element-Admin currently handles authentication across its three core layers.

### Login UI Component

The entry point for authentication is [`src/views/login/index.vue`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/views/login/index.vue), which collects user credentials and dispatches the `user/login` action. The `handleLogin` method validates the form and triggers the authentication process.

```javascript
// src/views/login/index.vue
handleLogin() {
  this.$refs.loginForm.validate(valid => {
    if (valid) {
      this.$store.dispatch('user/login', this.loginForm).then(() => {
        this.$router.push({ path: this.redirect || '/' })
      })
    }
  })
}

```

### Vuex Store Authentication Logic

The [`src/store/modules/user.js`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/store/modules/user.js) file contains the central authentication state management. The `login` action sends credentials to [`src/api/user.js`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/api/user.js) and stores the resulting JWT using `setToken` from [`src/utils/auth.js`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/utils/auth.js).

```javascript
// src/store/modules/user.js
login({ commit }, userInfo) {
  const { username, password } = userInfo
  return new Promise((resolve, reject) => {
    login({ username: username.trim(), password }).then(response => {
      const { data } = response
      commit('SET_TOKEN', data.token)
      setToken(data.token)
      resolve()
    }).catch(error => {
      reject(error)
    })
  })
}

```

### Token Persistence Layer

The [`src/utils/auth.js`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/utils/auth.js) utility abstracts token storage, typically using cookies or localStorage. This layer remains unchanged when implementing two-step verification, as it ultimately stores the final JWT after successful 2FA completion.

## Extending the System for Two-Step Login Verification

To implement two-step login verification, you need to modify the authentication flow to handle an intermediate state where the server requires an additional verification code.

### Step 1: Modify the Login Action to Handle 2FA Flags

Update [`src/store/modules/user.js`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/store/modules/user.js) to check for a `need2FA` flag in the login response. When this flag is true, store the temporary token and resolve with a status indicator instead of completing the authentication.

```javascript
// src/store/modules/user.js
const mutations = {
  SET_TOKEN: (state, token) => {
    state.token = token
  },
  SET_TEMP_TOKEN: (state, token) => {
    state.tempToken = token
  }
}

const state = {
  token: getToken(),
  tempToken: '',
  name: '',
  avatar: ''
}

login({ commit }, userInfo) {
  const { username, password } = userInfo
  return new Promise((resolve, reject) => {
    login({ username: username.trim(), password }).then(res => {
      const { data } = res
      if (data.need2FA) {
        commit('SET_TEMP_TOKEN', data.tempToken)
        resolve({ need2FA: true })
      } else {
        commit('SET_TOKEN', data.token)
        setToken(data.token)
        resolve({ need2FA: false })
      }
    }).catch(err => reject(err))
  })
}

```

### Step 2: Create the Verification Action

Add a new `verify2FA` action in [`src/store/modules/user.js`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/store/modules/user.js) that sends the OTP code and temporary token to the server. Upon successful verification, store the final JWT and clear the temporary token.

```javascript
// src/store/modules/user.js
verify2FA({ commit, state }, code) {
  return new Promise((resolve, reject) => {
    verify2FA({ token: state.tempToken, code }).then(res => {
      const { token } = res.data
      commit('SET_TOKEN', token)
      setToken(token)
      commit('SET_TEMP_TOKEN', '')
      resolve()
    }).catch(err => reject(err))
  })
}

```

### Step 3: Add the API Endpoint Wrapper

Extend [`src/api/user.js`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/api/user.js) to include the new verification endpoint that communicates with your backend.

```javascript
// src/api/user.js
export function verify2FA(data) {
  return request({
    url: '/vue-element-admin/user/verify-2fa',
    method: 'post',
    data
  })
}

```

### Step 4: Update the Login View Component

Modify [`src/views/login/index.vue`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/views/login/index.vue) to conditionally render a two-factor input form when the initial login response indicates 2FA is required.

```html
<!-- src/views/login/index.vue -->
<template>
  <div class="login-container">
    <!-- Standard Login Form -->
    <el-form v-if="!show2FA" ref="loginForm" :model="loginForm" :rules="loginRules">
      <el-form-item prop="username">
        <el-input v-model="loginForm.username" placeholder="Username" />
      </el-form-item>
      <el-form-item prop="password">
        <el-input v-model="loginForm.password" placeholder="Password" type="password" />
      </el-form-item>
      <el-button type="primary" @click="handleLogin">Login</el-button>
    </el-form>

    <!-- Two-Factor Verification Form -->
    <el-form v-else ref="faForm" @submit.native.prevent="handleVerify2FA">
      <el-form-item prop="code">
        <el-input v-model="twoFactorCode" placeholder="Enter OTP Code" maxlength="6" />
      </el-form-item>
      <el-button type="primary" @click="handleVerify2FA">Verify</el-button>
    </el-form>
  </div>
</template>

<script>
export default {
  data() {
    return {
      loginForm: {
        username: '',
        password: ''
      },
      show2FA: false,
      twoFactorCode: ''
    }
  },
  methods: {
    handleLogin() {
      this.$refs.loginForm.validate(valid => {
        if (valid) {
          this.$store.dispatch('user/login', this.loginForm).then(response => {
            if (response.need2FA) {
              this.show2FA = true
            } else {
              this.$router.push({ path: this.redirect || '/' })
            }
          })
        }
      })
    },
    handleVerify2FA() {
      this.$store.dispatch('user/verify2FA', this.twoFactorCode).then(() => {
        this.$router.push({ path: this.redirect || '/' })
      })
    }
  }
}
</script>

```

## Summary

Implementing two-step login verification in Vue-Element-Admin requires minimal changes to the existing authentication architecture:

- **Extend the Vuex store** ([`src/store/modules/user.js`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/store/modules/user.js)) with a `SET_TEMP_TOKEN` mutation and modify the `login` action to detect `need2FA` responses.
- **Add a verification action** (`verify2FA`) that exchanges the temporary token and OTP for the final JWT.
- **Create the API wrapper** ([`src/api/user.js`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/api/user.js)) for the `/user/verify-2fa` endpoint.
- **Update the login view** ([`src/views/login/index.vue`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/views/login/index.vue)) to conditionally render the OTP input form and handle the two-step flow.

This approach preserves the existing token persistence layer ([`src/utils/auth.js`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/utils/auth.js)) and permission system while adding robust two-factor authentication capabilities.

## Frequently Asked Questions

### How does the temporary token differ from the final JWT in the two-step verification flow?

The temporary token (stored via `SET_TEMP_TOKEN`) is a short-lived credential returned by the server during the first authentication step when `need2FA` is true. It cannot access protected routes or APIs; it exists solely to validate the OTP code in the second step. The final JWT (stored via `SET_TOKEN` and `setToken`) is the full authentication token issued only after successful two-step verification, which grants access to the application and is persisted in cookies or localStorage by [`src/utils/auth.js`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/utils/auth.js).

### Can I use this two-step verification implementation with external 2FA providers like Google Authenticator or Authy?

Yes, the implementation in [`src/store/modules/user.js`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/store/modules/user.js) and [`src/views/login/index.vue`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/views/login/index.vue) is provider-agnostic. The frontend only handles the OTP code input and passes it to your backend via the `verify2FA` action. Your backend (`/vue-element-admin/user/verify-2fa` endpoint) can validate the code against TOTP algorithms used by Google Authenticator, Authy, or SMS-based verification. The frontend changes remain identical regardless of which 2FA method your backend implements.

### What happens if a user refreshes the page during the two-step verification process?

If a user refreshes the page after completing the first step (when `show2FA` is true in [`src/views/login/index.vue`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/views/login/index.vue)) but before entering the OTP, the application state resets because `tempToken` is stored in Vuex state (memory) by default. To prevent users from restarting the login process, you can persist `tempToken` to `sessionStorage` in the `SET_TEMP_TOKEN` mutation within [`src/store/modules/user.js`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/store/modules/user.js), similar to how the final token uses [`src/utils/auth.js`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/utils/auth.js). However, ensure the temporary token has a short expiration on the backend to maintain security if persisted client-side.

### Do I need to modify the permission and routing guards when adding two-step verification?

No, the existing permission system in Vue-Element-Admin continues to function without modification. The routing guards in [`src/permission.js`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/permission.js) check for the presence of a valid token using `getToken()` from [`src/utils/auth.js`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/utils/auth.js). Since the `verify2FA` action in [`src/store/modules/user.js`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/store/modules/user.js) only sets the final token (via `setToken`) after successful two-step verification, the permission system naturally blocks access until the full authentication is complete. The temporary token used during the 2FA process is stored separately in Vuex state and is never checked by the routing guards.