Tauri Authentication
September 26, 2024
Add authentication to your app. Based on Tauri CRUD app.
What you will need:
- Tauri v2 - Version 2 of Tauri
- Tauri Store Plugin - for persistent key-value storage
- Tailwind CDN - for fast CSS styling
- Vue - frontend framework of choice
- Vue Router - for page routing
- Pinia - for state management and use with tauri store
Create a new Tauri App
Create a new tauri app and install dependencies
bash
nvm use 18.18.0
yarn create tauri-app --rc
cd tauri-app
yarn add pinia
yarn run tauri add store
yarn add vue-router
yarn
Basic Folder Structure
Some files and folders are not shown for simplicity.
app_name/
src/
main.js
/components
Nav.vue
Home.vue
Login.vue
Register.vue
stores/
store.js
Configuration
Set up some configuration for pinia
and vue-router
.
js
import { createApp } from "vue";
import { createMemoryHistory, createRouter, useRouter } from 'vue-router'
import { createPinia } from 'pinia'
import App from "./App.vue";
import Home from './components/Home.vue'
import Login from './components/Login.vue'
import Register from './components/Register.vue'
import { dataStore } from "../stores/store";
const pinia = createPinia()
const app = createApp(App)
app.use(pinia)
const store = dataStore();
const routes = [
{ name:'Home', path: '/', component: Home },
{ name: 'Login', path: '/login', component: Login },
{ name:'Register' ,path: '/register', component: Register },
]
const router = createRouter({
history: createMemoryHistory(),
routes,
})
router.beforeEach((to) => {
if (!store.loggedIn && to.name !=='Login' && to.name !=='Register'){
return '/login'
}
})
app.use(router)
app.mount("#app");
javascript
import { defineStore } from "pinia";
import { Store } from "@tauri-apps/plugin-store";
export const dataStore = defineStore("dataStore", {
state: () => {
return {
db: new Store("store.bin"),
users: [],
loggedIn: false,
}
},
getters: {
//
},
actions: {
//
}
});
The Code
All components live in /components/
.
You will need to click "Create Database" in order to create a new database or the app will error.
vue
<script setup>
import { ref, onMounted } from "vue";
import { dataStore } from "../../stores/store";
import { useRouter } from 'vue-router'
const store = dataStore();
const router = useRouter();
const user_form = ref({})
const all_users = ref([])
const showData = ref(false)
async function createUser(){
all_users.value.push(
{
id: all_users.value.length + 1,
email: user_form.value.email,
password: user_form.value.password,
}
)
await store.db.set('users', all_users.value)
await store.db.save()
setStatusMessage("User created successfully")
clearForm()
router.push('/login')
getAllUsers()
}
async function getAllUsers(){
all_users.value = await store.db.get('users')
}
function clearForm() {
document.getElementById("new-user-form").reset()
user_form.value = {}
}
function setStatusMessage(msg) {
document.getElementById("status-message").classList.remove("hidden")
setTimeout(() => {
document.getElementById("status-message").classList.add("hidden")
}, 5000)
document.getElementById("status-message").innerHTML = msg
}
// Left here if you need this. If you get an error, it may be because you haven't created the database.
async function createUserDatabase() {
await store.db.set('users', []);
}
// Left here if you need this.
async function deleteUserDatabase() {
await store.set('users', [])
setStatusMessage('Deleted All users in the DB')
getAllUsers()
}
onMounted(() => {
getAllUsers()
})
const name = ref("Register");
</script>
<template>
<div class="h-screen p-20 container mx-auto w-full bg-zinc-100 dark:bg-zinc-800 dark:text-white">
<form class="rounded-2xl bg-white dark:bg-zinc-900 p-20 mx-auto space-y-4" id="new-user-form" @submit.prevent="createUser()">
<h2 class="text-4xl">{{name}}</h2>
<div>
<button @click.prevent="createUserDatabase()">Create Database</button>
<button @click.prevent="deleteUserDatabase()" class="ml-2">Delete User Database</button>
</div>
<div>
<label for="email">Email</label><br>
<input class="w-full mt-2 border p-2 rounded-lg dark:bg-zinc-800 dark:text-white bg-zinc-100" v-model="user_form.email" name="email">
</div>
<div>
<label for="password">Password</label><br>
<input class="w-full mt-2 border p-2 rounded-lg dark:bg-zinc-800 dark:text-white bg-zinc-100" v-model="user_form.password" name="password">
</div>
<input type="submit" class="bg-blue-500 text-white py-2 px-4 rounded-lg font-semibold"><br>
<button @click.prevent="showData=!showData" class="bg-black text-white p-1 text-xs px-2 rounded-md">Toggle Data</button>
<p v-if="showData" class="mt-2 dark:bg-zinc-800 dark:text-white p-2 rounded-lg">{{all_users}}</p>
</form>
</div>
</template>
vue
<script setup>
import { ref, onMounted } from "vue";
import { dataStore } from "../../stores/store";
import { useRouter } from 'vue-router'
const store = dataStore();
const router = useRouter();
const user_form = ref({})
const all_users = ref([])
const showData = ref(false)
const retrieved = ref()
async function retrieveUser(){
const val = await store.db.get('users')
const user = val.find(obj=> obj['email'] === user_form.value.email && obj['password'] === user_form.value.password)
if (user!=null){
setStatusMessage(`Retrieved ${user.email}`)
retrieved.value = user
store.loggedIn = true
router.push('/')
return user
}else{
setStatusMessage("User doesn't exist")
}
}
async function getAllUsers(){
all_users.value = await store.db.get('users')
}
function clearForm() {
document.getElementById("new-user-form").reset()
user_form.value = {}
}
function setStatusMessage(msg) {
document.getElementById("status-message").classList.remove("hidden")
setTimeout(() => {
document.getElementById("status-message").classList.add("hidden")
}, 5000)
document.getElementById("status-message").innerHTML = msg
}
onMounted(() => {
getAllUsers()
})
const name = ref("Login");
</script>
<template>
<div class="h-screen p-20 container mx-auto w-full bg-zinc-100 dark:bg-zinc-800 dark:text-white">
<form class="rounded-2xl bg-white dark:bg-zinc-900 p-20 mx-auto space-y-4" id="new-user-form" @submit.prevent="retrieveUser()">
<h2 class="text-4xl">{{name}}</h2>
<div>
<label for="email">Email</label><br>
<input spellcheck="false" class="w-full mt-2 border p-2 rounded-lg dark:bg-zinc-800 dark:text-white bg-zinc-100" v-model="user_form.email" name="email">
</div>
<div>
<label for="password">Password</label><br>
<input spellcheck="false" class="w-full mt-2 border p-2 rounded-lg dark:bg-zinc-800 dark:text-white bg-zinc-100" v-model="user_form.password" name="password">
</div>
{{retrieved}}
<input type="submit" class="bg-blue-500 text-white px-4 py-2 rounded-lg font-semibold"><br>
<button @click.prevent="showData=!showData" class="bg-black text-white p-1 text-xs px-2 rounded-md">Toggle Data</button>
<p v-if="showData" class="mt-2 dark:bg-zinc-800 dark:text-white p-2 rounded-lg">{{user_form}}</p>
</form>
</div>
</template>
html
<script setup>
import { ref } from "vue";
import { dataStore } from "../../stores/store";
const store = dataStore();
</script>
<template>
<div class="bg-white dark:bg-zinc-900 dark:text-white sticky top-0 z-50 ">
<nav class="p-4 border-b-2 border-zinc-200">
<ul class="flex items-center justify-start">
<li>
<router-link to="/">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="bi bi-list"
viewBox="0 0 16 16">
<path fill-rule="evenodd"
d="M2.5 12a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5z">
</path>
</svg>
</router-link>
</li>
<li>
<router-link to="/"><img src="/up_dark.png" class="ml-2 w-8 h-8 logo vite" alt="Vite logo" />
</router-link>
</li>
<li class="ml-auto">
<p id="status-message" class="hidden rounded-lg bg-yellow-200 border border-yellow-800 text-yellow-800 p-2">
status message</p>
</li>
<li v-if="store.loggedIn == true" @click="store.loggedIn = false" class="ml-auto flex items-center">
<span class="ml-2"><router-link to="/login" class="px-5 p-[.2rem] bg-zinc-200 dark:bg-zinc-800 flex items-center rounded-full">
Logout
</router-link></span>
</li>
<li v-if="store.loggedIn == false" class="ml-auto flex items-center">
<span class="ml-2"><router-link to="/login" class="px-5 p-[.2rem] bg-zinc-200 dark:bg-zinc-800 flex items-center rounded-full">
Login
</router-link></span>
</li>
<li v-if="store.loggedIn == false" class="ml-4 flex items-center">
<span class="ml-2"><router-link to="/register"
class="px-5 p-[.2rem] bg-zinc-200 dark:bg-zinc-800 flex items-center rounded-full">
Register
</router-link></span>
</li>
</ul>
</nav>
</div>
</template>
html
<script setup>
import { ref } from "vue";
const name = ref("Home");
</script>
<template>
<h1>{{name}}</h1>
</template>
Test the App
yarn tauri dev
Build the App for Release
yarn tauri build