> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hanko.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Integrate Hanko with Vue

> Learn how to quickly add authentication and user profile in your Vue app using Hanko.

<div class="hidden">
  **Hanko Frontend Integration Guide**:

  **About Hanko**:

  Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours.

  **What This Guide Covers**: This guide demonstrates how to integrate Hanko authentication into your frontend application. You'll implement user authentication, profile management, route protection, and logout functionality with Hanko Elements web components.

  **Key Technologies**:

  * Modern frontend framework with TypeScript support
  * Build tools and development environment
  * Client-side routing and navigation
  * Hanko Elements web components
  * Hanko SDK for authentication logic

  **Prerequisites**:

  * Node.js installed on your system
  * Basic knowledge of your chosen frontend framework
  * A Hanko Cloud account (sign up at cloud.hanko.io)

  **Integration Tasks You'll Complete**:

  * Set up your frontend application with the appropriate build tools
  * Install and configure Hanko Elements
  * Create a Hanko project in the cloud console
  * Implement authentication components (HankoAuth, HankoProfile)
  * Set up routing and navigation
  * Add logout functionality
  * Implement protected routes with session validation
  * Retrieve and display user data
  * Customize component styling and behavior
</div>

## Create a Vue application

Run the following command to [create a new Vue application with vite](https://vite.dev/guide/):

<CodeGroup>
  ```bash npm theme={null}
  npm create vite@latest project-name -- --template vue-ts
  ```

  ```bash pnpm theme={null}
  pnpm create vite project-name --template vue-ts
  ```

  ```bash bun theme={null}
  bun create vite project-name --template vue-ts
  ```

  ```bash yarn theme={null}
  yarn create vite project-name --template vue-ts
  ```
</CodeGroup>

## Install `@teamhanko/hanko-elements`

Install `hanko-elements` to access the pre-built `hanko-auth` and `hanko-profile` components.

Also install `vue-router` to handle routing and navigation.

<CodeGroup>
  ```bash npm theme={null}
  cd project-name
  npm install @teamhanko/hanko-elements vue-router
  ```

  ```bash pnpm theme={null}
  cd project-name
  pnpm add @teamhanko/hanko-elements vue-router
  ```

  ```bash bun theme={null}
  cd project-name
  bun add @teamhanko/hanko-elements vue-router
  ```

  ```bash yarn theme={null}
  cd project-name
  yarn add @teamhanko/hanko-elements vue-router
  ```
</CodeGroup>

## Set up your Hanko project

Go to the [Hanko Console](https://cloud.hanko.io/) and [create a project for this application.](/setup-hanko-cloud)

<Note>
  During creation make sure to input the URL you will be developing on as the `APP URL`.\
  (Most likely [http://localhost:5173/](http://localhost:5173/))
</Note>

## Add the Hanko API URL

Retrieve your API URL from the [Hanko Console](https://cloud.hanko.io/), and paste this in a `.env` file.

```sh .env theme={null}
VITE_HANKO_API_URL=https://f4****-4802-49ad-8e0b-3d3****ab32.hanko.io
```

<Note>
  If you are self-hosting you need to provide the URL of your running Hanko backend.
</Note>

## Configure component resolution

Vue needs to know which elements to treat as custom elements, otherwise it will issue a warning regarding component
resolution. To do so, provide a predicate function that determines which elements are to be considered custom elements
to [`compilerOptions.isCustomElement`](https://vuejs.org/guide/extras/web-components.html#using-custom-elements-in-vue)
in your configuration.\
\
To do this update your `vite.config.js` file to:

```js src/vite.config.js theme={null}
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue({
    template: {
        compilerOptions: {
          isCustomElement: (tag) => tag.startsWith("hanko-")
        }
    }
    })],
})
```

## Set up TS support for Vue components

TypeScript doesn't understand .vue files by default, which can cause IDE errors or issues during development.

To fix this we will create a new file `shims-vue.d.ts` in our `src/` directory.
Add the following content to make TS understand .vue files:

```jsx src/shims-vue.d.ts theme={null}
declare module '*.vue' {
  import type { DefineComponent } from 'vue'
  const component: DefineComponent<{}, {}, any>
  export default component
}

```

## Create Hanko components

Create a folder called `components` and create two in it, `HankoAuth.vue` and `HankoProfile.vue`.

### Hanko Auth

Set up the `HankoAuth.vue` file to create a functioning login component.

Here we subscribe to the `onSessionCreated` [event](/guides/hanko-elements/using-frontend-sdk#events), this triggers when a user successfully logs in. You can use these event to perform any desired action (e.g. redirect to your dashboard).

For more information please refer to the [Auth component page.](/guides/hanko-elements/auth-component)

```jsx src/components/HankoAuth.vue  theme={null}
<script setup lang="ts">
  import { useRouter } from "vue-router";
  import { onMounted } from "vue";
  import { register } from "@teamhanko/hanko-elements";

  const hankoApi = import.meta.env.VITE_HANKO_API_URL;
  const router = useRouter();

  const redirectAfterLogin = () => {
    // successfully logged in, redirect to a page in your application
    router.push("/dashboard");
  };

  onMounted(() => {
    register(hankoApi)
      .catch((error) => {
        // handle error
        console.log(error);
      });
  });
</script>

<template>
<!-- The onSessionCreated event gets called when the user succesfully logs in -->
<hanko-auth @onSessionCreated="redirectAfterLogin" />
</template>
```

### Hanko Profile

Set up the `HankoProfile.vue` file to create an interface where users can manage their email addresses and credentials.

For more information please refer to the [Profile component page.](/guides/hanko-elements/profile-component)

```jsx src/components/HankoProfile.vue theme={null}
  <script setup lang="ts">
    import { onMounted } from "vue";
    import { register } from "@teamhanko/hanko-elements";

    const hankoApi = import.meta.env.VITE_HANKO_API_URL;

    onMounted(() => {
      register(hankoApi).catch((error) => {
        // handle error
        console.log(error)
      });
    });
  </script>

  <template>
    <hanko-profile />
  </template>
```

## Set up routes and views

To route our app we will use the `RouterView` component from the vue-router.
First let's set up our views which will be used by the router.

### Create Views

Create two files, `HomeView.vue` and `DashboardView.vue` in a new directory `/views`.
These Views will be the content that will be shown on a page.\
\
Setup your views like this:

```jsx src/views/HomeView.vue theme={null}
<script setup lang="ts">
  import HankoAuth from '../components/HankoAuth.vue'
</script>

<template>
  <main>
    <HankoAuth/>
  </main>
</template>
```

And:

```jsx src/views/DashboardView.vue theme={null}
<script setup lang="ts">
  import HankoProfile from '../components/HankoProfile.vue'
</script>

<template>
  <main>
    <HankoProfile/>
  </main>
</template>
```

### Set up router

Create a file `index.ts` in a new directory `/router`.
In here we can set up the `vue-router` just like this:

```jsx router/index.ts theme={null}
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue';
import DashboardView from '../views/DashboardView.vue';

const router = createRouter({
    history: createWebHistory(import.meta.env.BASE_URL),
    routes: [
      {
        path: '/', // <- path
        name: 'home',
        component: HomeView // <- view
      },
      {
        path: '/dashboard', // <- path
        name: 'dashboard',
       component: DashboardView // <- view
      }
    ]
  })

export default router
```

Add the `<RouterView>` component to your `App.vue` file like this:

```jsx src/App.vue theme={null}
  <script setup lang="ts">
    import { RouterView } from 'vue-router'
  </script>

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

Finally intergrate the router with the app in `main.ts` just like this:

```jsx src/main.ts theme={null}
  import { createApp } from 'vue'
  import App from './App.vue'
  import router from './router/index'

  const app = createApp(App)

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

By now you should be able to go to `/` to see the `<HankoAuth>`, and to `/dashboard` to see the `<HankoProfile>`.

They should look something like this👇

<Frame>
  <div style={{justifyContent: 'center', alignItems: 'center', display: 'flex', backgroundColor: 'white'}}>
    <img src="https://mintcdn.com/hanko/nDll7gWf2olRVk-k/images/fullstack-guide/next-one.png?fit=max&auto=format&n=nDll7gWf2olRVk-k&q=85&s=cfa08b5e9e30da72781967f53165a313" alt="sign up" width="500" data-path="images/fullstack-guide/next-one.png" />

    <img src="https://mintcdn.com/hanko/nDll7gWf2olRVk-k/images/fullstack-guide/next-two.png?fit=max&auto=format&n=nDll7gWf2olRVk-k&q=85&s=ddd4d20a613d80fcb7004d677fee3ed9" alt="profile page" width="500" data-path="images/fullstack-guide/next-two.png" />
  </div>
</Frame>

<Note>
  If `HankoAuth` is not loading please restart the application as it might've not loaded the .env correctly the first time.\
  \
  `HankoProfile` will only look like the picture while you are logged in.
</Note>

## Implement logout functionality

You can use `@teamhanko/hanko-elements` to easily logout users. Here we will make a logout button.

Create `LogoutButton.vue` and insert the code below.

```jsx src/components/LogoutButton.vue theme={null}
  <script setup lang="ts">
    import { useRouter } from "vue-router";
    import { Hanko } from "@teamhanko/hanko-elements";

    const hankoApi = import.meta.env.VITE_HANKO_API_URL;

    const router = useRouter();
    const hanko = new Hanko(hankoApi);

    const logout = () => {
      hanko.logout().catch((error) => {
        // handle error
        console.log(error)
      })
      router.push("/")//Path user will be redirected to after logging out
    }
  </script>

  <template>
    <button @click="logout">Logout</button>
  </template>
```

Lets add this component to our `DashboardView` just like this:

```jsx src/views/DashboardView.vue theme={null}
<script setup lang="ts">
  import HankoProfile from '../components/HankoProfile.vue'
  import LogoutButton from '../components/LogoutButton.vue'
</script>

<template>
  <main>
    <HankoProfile/>
    <LogoutButton/>
  </main>
</template>
```

## Customize component styles

You can customize the appearance of `hanko-auth` and `hanko-profile` components using CSS variables and parts. Refer to our [customization guide](/guides/hanko-elements/customize-appearance).

## Securing routes

To secure our routes we should validate the session token at the backend. Please refer to our [backend guides](/quickstarts/backend).

To do this we can implement middleware to our `router/index.ts` file.
For this example we created a `isUserAuthenticated` function which validates our cookie using our Backend.

Here we use `router.beforeEach` to validate our route if our route is added to the secureRoutes variable:

```jsx src/router/index.ts theme={null}
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue';
import DashboardView from '../views/DashboardView.vue';

//Routes we want to only be accesible to authenticated users
const securedRoutes = ["dashboard"];

async function isUserAuthenticated() {
  try {
    //Change this url to the url of your running hanko backend
    const response = await fetch('http://localhost:5001/validate', {
      credentials: 'include',
    });
    return response.ok;
  } catch (error) {
    return false;
  }
}

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/', // <- path
      name: 'home',
      component: HomeView // <- view
    },
    {
      path: '/dashboard', // <- path
      name: 'dashboard',
      component: DashboardView // <- view
    }
  ]
})

//Middleware that runs before each navigation
router.beforeEach(async (to, from, next) => {
  //Check if you are on a secure route
  if (typeof to.name === "string" && securedRoutes.includes(to.name) && !(await isUserAuthenticated())) {
    next({ name: 'home' }); //Name of the route to redirect to if user is not authenticated
  } else {
    next();
  }
});

export default router
```

To verify that it works, Logout on your app and go to /dashboard, you should get redirected back!

## Try it yourself

<Card
  title="Vue example"
  href="https://github.com/teamhanko/hanko-vue-express-starter"
  icon={
<svg
  xmlns="http://www.w3.org/2000/svg"
  className="icon icon-tabler icon-tabler-external-link"
  width="24"
  height="24"
  viewBox="0 0 24 24"
  strokeWidth="2"
  stroke="#5465FF"
  fill="none"
  strokeLinecap="round"
  strokeLinejoin="round"
>
  <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
  <path d="M12 6h-6a2 2 0 0 0 -2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-6"></path>
  <path d="M11 13l9 -9"></path>
  <path d="M15 4h5v5"></path>
</svg>
}
>
  It uses Express.js for the backend, full source code available on our GitHub.
</Card>
