> For the complete documentation index, see [llms.txt](https://fusionauth.io/docs/llms.txt)

# Vue.js | FusionAuth Docs

Quickstart integration of a Vue.js web application with FusionAuth.

# Vue.js

[Edit on GitHub](https://github.com/FusionAuth/fusionauth-site/blob/main/astro/src/content/docs/get-started/quickstarts/spa/quickstart-javascript-vue-web.mdx)

[View Markdown](https://fusionauth.io/docs/get-started/quickstarts/spa/quickstart-javascript-vue-web.md)

In this quickstart, you are going to build an application with Vue.js and integrate it with FusionAuth. You'll be building it for [ChangeBank](https://www.youtube.com/watch?v=CXDxNCzUspM), a global leader in converting dollars into coins. It'll have areas reserved for users who have logged in as well as public facing sections.

The Docker Compose file and source code for a complete application are available at [https://github.com/FusionAuth/fusionauth-quickstart-javascript-vue-web](https://github.com/FusionAuth/fusionauth-quickstart-javascript-vue-web).

## Prerequisites[#](#prerequisites)

*   [Node v18](https://nodejs.org/en): This will be used to run the Vue.js application.
*   [Docker](https://www.docker.com): The quickest way to stand up FusionAuth. (There are [other ways](https://fusionauth.io/docs/get-started/download-and-install.md)).

This app has been tested with Node v18 and Vue.js v3.3.4. This example should work with other compatible versions of Node and Vue.js.

## General Architecture[#](#general-architecture)

While this sample application doesn't have login functionality without FusionAuth, a more typical integration will replace an existing login system with FusionAuth. In that case, the system might look like this before FusionAuth is introduced.

```mermaid
sequenceDiagram
    participant User
    participant App as Application

    User ->> App : View Homepage
    User ->> App : Click Login Link
    App ->> User : Show Login Form
    User ->> App : Fill Out and Submit Login Form
    App ->> App : Authenticates User
    App ->> User : Display User's Account or Other Info
```

Request flow during login before FusionAuth

And here's the same application login flow after introducing FusionAuth.

```mermaid
sequenceDiagram
    participant User
    participant App as Application
    participant FusionAuth

    User ->> App : View Homepage
    User ->> App : Click Login Link (to FusionAuth)
    User ->> FusionAuth : View Login Form
    FusionAuth ->> User : Show Login Form
    User ->> FusionAuth : Fill Out and Submit Login Form
    FusionAuth ->> FusionAuth : Authenticates User
    FusionAuth ->> User: Go to Redirect URI
    User ->> App: Request the Redirect URI
    App ->> FusionAuth : Is User Authenticated?
    FusionAuth ->> App : User is Authenticated
    App ->> User : Display User's Account or Other Info
```

Request flow during login after FusionAuth

In general, you are introducing FusionAuth in order to normalize and consolidate user data. This helps make sure it is consistent and up-to-date as well as offloading your login security and functionality to FusionAuth.

## Getting Started[#](#getting-started)

In this section, you'll get FusionAuth up and running and use Vue.js CLI to create a new application.

### Clone The Code[#](#clone-the-code)

First off, grab the code from the repository and change into that directory.

```shell
git clone https://github.com/FusionAuth/fusionauth-quickstart-javascript-vue-web.git
cd fusionauth-quickstart-javascript-vue-web
```

### Run FusionAuth Via Docker[#](#run-fusionauth-via-docker)

You'll find a Docker Compose file (`docker-compose.yml`) and an environment variables configuration file (`.env`) in the root directory of the repo.

Assuming you have Docker installed, you can stand up FusionAuth on your machine with the following.

```shell-session
docker compose up -d
```

Here you are using a bootstrapping feature of FusionAuth called [Kickstart](https://fusionauth.io/docs/get-started/download-and-install/development/kickstart.md). When FusionAuth comes up for the first time, it will look at the `kickstart/kickstart.json` file and configure FusionAuth to your specified state.

If you ever want to reset the FusionAuth application, you need to delete the volumes created by Docker Compose by executing `docker compose down -v`, then re-run `docker compose up -d`.

FusionAuth will be initially configured with these settings:

*   Your client Id is `e9fdb985-9173-4e01-9d73-ac2d60d1dc8e`.
*   Your client secret is `super-secret-secret-that-should-be-regenerated-for-production`.
*   Your example username is `richard@example.com` and the password is `password`.
*   Your admin username is `admin@example.com` and the password is `password`.
*   The base URL of FusionAuth is `http://localhost:9011/`.

You can log in to the [FusionAuth admin UI](http://localhost:9011/admin) and look around if you want to, but with Docker and Kickstart, everything will already be configured correctly.

If you want to see where the FusionAuth values came from, they can be found in the [FusionAuth app](http://localhost:9011/admin). The tenant Id is found on the Tenants page. To see the Client Id and Client Secret, go to the Applications page and click the `View` icon under the actions for the ChangeBank application. You'll find the Client Id and Client Secret values in the `OAuth configuration` section.

The `.env` file contains passwords. In a real application, always add this file to your `.gitignore` file and never commit secrets to version control.

### Create A Basic Vue.js Application[#](#create-a-basic-vuejs-application)

Now you are going to create a basic Vue.js application using Create Vue. While this section builds a simple Vue.js application, you can use the same configuration to integrate your existing Vue.js application with FusionAuth.

```shell
npm create vue@latest -- changebank --typescript --router
```

We are going to use the [Hosted Backend](https://fusionauth.io/docs/apis/hosted-backend.md) feature of FusionAuth, so you don't need to worry about setting up a backend server.

While this example uses localhost for your application and FusionAuth, there are complications if you plan to deploy using FusionAuth Cloud.

When developing against a FusionAuth Cloud instance with a hostname ending in `fusionauth.io`, unless your application shares the same domain of `fusionauth.io` attempts to use these endpoints will fail with a `403` status code.

These endpoints do not work correctly for cross origin requests. Cross origin requests occur when the application making the request to FusionAuth is using a separate domain. For example, if your application URL is `app.acme.com` and the FusionAuth URL is `acme.fusionauth.io` requests from your application to FusionAuth will be considered cross origin.

If possible, have FusionAuth and your application served by the same domain, using a [proxy if needed](https://fusionauth.io/docs/operate/deploy/proxy-setup.md). For example, serve your app from `app.acme.com` and FusionAuth from `auth.acme.com`.

If this configuration is not possible, use one of these alternative methods:

*   Develop using a local FusionAuth instance, so both your webapp and FusionAuth are running on `localhost`.
*   Do not use the FusionAuth hosted backend, and instead write your own backend with a cross origin cookie policy: [here’s an example](https://github.com/FusionAuth/fusionauth-javascript-sdk-express/tree/main).
*   Configure a [custom domain name for the FusionAuth Cloud instance](https://fusionauth.io/docs/get-started/run-in-the-cloud/cloud.md#updating-with-existing-custom-domains).

Modifying FusionAuth CORS configuration options does not fix this issue because the cookies that FusionAuth writes will not be accessible cross domain.

First, install the FusionAuth Vue SDK:

```shell
npm install @fusionauth/vue-sdk
```

Next, you'll need to configure and activate the FusionAuth Vue SDK. You can do this by updating the `src/main.ts` file contents. Replace what is there with this:

```typescript
import './assets/main.css'
import '@fusionauth/vue-sdk/dist/style.css';

import {createApp} from 'vue'
import App from './App.vue'
import router from './router'
import FusionAuthVuePlugin from '@fusionauth/vue-sdk';

const app = createApp(App)

app.use(FusionAuthVuePlugin, {
  clientId: 'e9fdb985-9173-4e01-9d73-ac2d60d1dc8e',
  serverUrl: 'http://localhost:9011',
  redirectUri: 'http://localhost:5173',
  postLogoutRedirectUri: 'http://localhost:5173/logged-out',
  shouldAutoFetchUserInfo: true,
  shouldAutoRefresh: true,
  scope: 'openid email profile offline_access'
});

app.use(router)

app.mount('#app')
```

Our example application is going to have a home page, an account page and a page where someone can make change. The account and make change page will be protected and only visible to logged in users.

#### Create A Home Page[#](#create-a-home-page)

The next step is to get a basic home page up and running. We'll take this opportunity to copy in all the images and CSS style files that you'll need for the application.

Run the following copy command to copy these files from the quickstart repo into your project. This assumes that you checked the quickstart repo out into the parent directory. If that's not the case, replace the `..` below with your actual repo location.

```shell
cp -r ../complete-application/src/assets src
```

The home page will be a simple page with a welcome message and a login link. Replace the content of the file `src/views/HomeView.vue`:

```markup
<template>
  <div class="column-container">
    <div class="content-container">
      <div>
        <h1>Welcome to Changebank</h1>
          <p>
            Login or create a new account to get started
          </p>
            <button className="button-lg" style = "cursor: pointer"  @click="fusionAuth.login()">
            Login
            </button>
            <br/>
            <button className="button-redirect" style = "cursor: pointer"  @click="fusionAuth.register()">
            Create a new account.
            </button>
      </div>
    </div>

    <div class="image-container">
      <img src="@/assets/money.jpg" alt="Coins"/>
    </div>
  </div>
</template>

<script setup lang="ts">
import {useFusionAuth} from "@fusionauth/vue-sdk";

const fusionAuth = useFusionAuth();

</script>
```

#### Create An Account Page[#](#create-an-account-page)

The account page displays a random balance for the logged in user. Create a new file `src/views/AccountView.vue`:

```markup
<template>
  <div class="column-container">
    <div class="app-container">
      <h3>Your Balance</h3>
      <div class="balance">{{ balance }}</div>
    </div>
  </div>
</template>

<script setup lang="ts">
let dollarUS = Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  useGrouping: false,
});
const balance = dollarUS.format(Math.ceil(Math.random() * 100000) / 100);
</script>
```

#### Create A Make Change Page[#](#create-a-make-change-page)

Next, you'll create a page only visible to logged in users. This page displays an input field for the user to enter a dollar amount and a button to convert that amount into coins. Create a new file `src/views/MakeChangeView.vue`:

```markup
<template>
  <div class="app-container change-container">
    <h3>Make Change</h3>

    <form @submit="makeChange">
        <div class="change-label">Amount in USD</div>
        <input class="change-input" name="amount" type="number" step=".01" v-model="amount"/>
        <input class="change-submit" type="submit" value="Make Change"/>
    </form>
    <div class="change-message" v-if="change">
      We can make change for {{ dollarUS.format(change.total) }} with {{ change.nickels }} nickels and {{ change.pennies }} pennies!
    </div>
  </div>
</template>

<script setup lang="ts">
import {ref} from "vue";

const amount = ref<number>(0);
const change = ref<{ total: number; nickels: number; pennies: number } | null>();

let dollarUS = Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  useGrouping: false,
});

const makeChange = (e: Event) => {
  e.stopPropagation();
  e.preventDefault();

  const total = amount.value;
  const nickels = Math.floor(amount.value / 0.05);
  const pennies = Math.round((amount.value - nickels * 0.05) * 100);
  change.value = {total, nickels, pennies};
};
</script>
```

## Authentication[#](#authentication)

You now have created a basic Vue.js application with a home page, account page and a page for making change.

Depending on the user's authentication state, the login or logout button should be displayed in the header. For this create a new file `src/components/LogoHeader.vue`:

```markup
<template>
  <div id="logo-header">
    <img src="@/assets/changebank.svg" alt="Change Bank" width="259" height="70"/>

    <RequireAuth>
      <div class="h-row">
        <p class="header-email" v-if="userInfo?.email">
          {{ userInfo.email }}
        </p>
        <a class="button-lg" style="cursor: pointer" @click="logout()">Logout</a>
      </div>
    </RequireAuth>

    <RequireAnonymous>
      <a class="button-lg" style="cursor: pointer" @click="login()">Login</a>
    </RequireAnonymous>

  </div>
</template>

<script setup lang="ts">
import {useFusionAuth} from "@fusionauth/vue-sdk";

const {userInfo, login, logout} = useFusionAuth();
</script>
```

Additionally, we want to display different menu items. For this create a new file `src/components/MenuBar.vue`:

```jsx
<template>
  <div id="menu-bar" class="menu-bar">
    <RequireAuth>
      <router-link to="/account" class="menu-link" active-class="active">Account</router-link>
      <router-link to="/make-change" class="menu-link" active-class="active">Make Change</router-link>
    </RequireAuth>

    <RequireAnonymous>
      <a class="menu-link" style="text-decoration: underline">Home</a>
      <a class="menu-link">Products</a>
      <a class="menu-link">Services</a>
      <a class="menu-link">About</a>
    </RequireAnonymous>
  </div>
</template>
```

The next step is to tie it all together. Update the `src/App.vue` file to add the router view and header. You can replace the contents of the file with the below:

```markup
<script setup lang="ts">
import {RouterView} from 'vue-router'
import MenuBar from "@/components/MenuBar.vue";
import LogoHeader from "@/components/LogoHeader.vue";
</script>

<template>
  <div id="page-container">
    <div id="page-header">
      <LogoHeader/>
      <MenuBar/>
    </div>

    <div>
      <RouterView/>
    </div>
  </div>
</template>
```

And finally we register the routes in `src/router/index.ts`. Update that file with the code below.

```typescript
import {createRouter, createWebHistory} from 'vue-router'
import HomeView from '../views/HomeView.vue'
import {useFusionAuth} from "@fusionauth/vue-sdk";

const routeGuard = (loggedIn: boolean, fallback: string) => {
  return () => {
    const fusionAuth = useFusionAuth();
    if (fusionAuth.isLoggedIn.value !== loggedIn) {
      return fallback;
    }
  }
}

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/',
      name: 'home',
      component: HomeView,
      beforeEnter: routeGuard(false, '/account'),
      alias: '/logged-out'
    },
    {
      path: '/account',
      name: 'account',
      component: () => import('../views/AccountView.vue'),
      beforeEnter: routeGuard(true, '/')
    },
    {
      path: '/make-change',
      name: 'make-change',
      component: () => import('../views/MakeChangeView.vue'),
      beforeEnter: routeGuard(true, '/')
    },
    {path: '/:pathMatch(.*)*', redirect: '/'},
  ]
})

export default router
```

## Running The Application[#](#running-the-application)

You can now run the application with the following command:

```shell
npm run dev
```

You can now open up an incognito window and navigate to [http://localhost:5173](http://localhost:5173). You will be greeted with the home page. Log in with the user account you created when setting up FusionAuth, and you'll be redirected to the account page.

The username and password of the `example user` can be found in the [FusionAuth via Docker](#run-fusionauth-via-docker) section at the top of this article.

## Made it this far? Want a free t-shirt? We got ya.

Thank you for spending some time getting familiar with FusionAuth.

\*Offer only valid in the United States and Canada, while supplies last.

## Next Steps[#](#next-steps)

This quickstart is a great way to get a proof of concept up and running quickly, but to run your application in production, there are some things you're going to want to do.

### FusionAuth Customization

FusionAuth gives you the ability to customize just about everything to do with the user's experience and the integration of your application. This includes:

*   [Hosted pages](https://fusionauth.io/docs/customize/look-and-feel.md) such as login, registration, email verification, and many more.
*   [Email templates](https://fusionauth.io/docs/customize/email-and-messages/email-templates.md).
*   [User data and custom claims in access token JWTs](https://fusionauth.io/articles/tokens/jwt-components-explained.md).

### Security

*   You may want to customize the [token expiration times and policies](https://fusionauth.io/docs/lifecycle/authenticate-users/oauth.md) in FusionAuth.
*   Choose [password rules](https://fusionauth.io/docs/get-started/core-concepts/tenants.md#password) and a [hashing algorithm](https://fusionauth.io/docs/reference/password-hashes.md) that meet your security needs.

### Tenant and Application Management

*   Model your application topology using [Applications](https://fusionauth.io/docs/get-started/core-concepts/applications.md), [Roles](https://fusionauth.io/docs/get-started/core-concepts/roles.md), [Groups](https://fusionauth.io/docs/get-started/core-concepts/groups.md), [Entities](https://fusionauth.io/docs/get-started/core-concepts/groups.md), and more.
*   Set up [MFA](https://fusionauth.io/docs/lifecycle/authenticate-users/multi-factor-authentication.md), [Social login](https://fusionauth.io/docs/lifecycle/authenticate-users/identity-providers.md), or [SAML](https://fusionauth.io/docs/lifecycle/authenticate-users/identity-providers/overview-samlv2.md) integrations.
*   Integrate with external systems using [Webhooks](https://fusionauth.io/docs/extend/events-and-webhooks.md), [SCIM](https://fusionauth.io/docs/lifecycle/migrate-users/scim.md), and [Lambdas](https://fusionauth.io/docs/extend/code/lambdas.md).