Login Component in Nuxt (Rest Strapi)
Simple example of login page in nuxt3 written as base to copy and paste in many similar projects.
Daniel Gustaw
• 4 min read
How many times in your live did you implemented login view? I did it too much times. Finally to no search code to copy in my projects I decided to paste here easy instruction how to build simple login component in nuxt.
This setup using strapi as backend, but I will works with any rest API after body and url modifications. In next part we will create nuxt3 project, build login page and pass info about user by cookie to profile component.
Setup Nuxt project
To create project:
npx nuxi init front_nuxt
We can create universal Makefile
to start project by make up
node_modules: package.json
npm i
up: node_modules
npm run dev
Now to start coding we have to replace:
<NuxtWelcome />
in app.vue
by
<NuxtPage />
First page (login)
Now create first page
npx nuxi add page login
We need to login by REST
api but instead of axios
we will use useFetch
available in nuxt. To achieve this goal we have to add .env
file with
NUXT_PUBLIC_BASE_URL=http://localhsot:1337
and prepend lines
include .env
export
to the Makefile
to read .env
without dotenv
package.
To nuxt.config.ts
we have to add
runtimeConfig: {
public: {
baseUrl: process.env.NUXT_PUBLIC_BASE_URL,
},
},
Now in script
of pages/login.vue
we can define formBody
and requestBody
import {ref, useLazyFetch, useRuntimeConfig} from "#imports";
const config = useRuntimeConfig();
const formBody = ref<{ identifier: string, password: string }>({
identifier: '[email protected]',
password: 'pass'
});
const requestBody = ref<{ identifier: string, password: string }>({
identifier: '',
password: ''
});
different variables are consequence of reactivity of useLazyFetch
method that will automatically send http request when requestBody
will be changed. So to allow modify formBody
without sending http
requests we have to split them to two distinct reactive references.
Our request will be performed by useLazyFetch
const {data, error, pending} = await useLazyFetch(`${config.public.baseUrl}/api/auth/local`, {
body: requestBody,
method: 'post',
immediate: false,
watch: [],
})
finally we can define login
function that trigger http request simply changing body in useLazyFetch
options.
async function login() {
requestBody.value = formBody.value;
}
In template we adding super minimalistic frontend with login form and pre
tags to present data:
<template>
<div>
<pre>PENDING: {{ pending }}</pre>
<pre>DATA: {{ data }}</pre>
<pre>ERROR: {{ error }}</pre>
<hr>
<form @submit.prevent="login">
<label for="email">
Email
<input type="text" v-model.lazy="formBody.identifier">
</label>
<label for="password">
Password
<input type="password" v-model.lazy="formBody.password">
</label>
<button>Login</button>
</form>
</div>
</template>
Passing user token between components
To share state between components we can use store like pinia
, that can be persisted by local-sorage
. Other solution is cookie
. In our case we will show cokkie implementation because it is build in nuxt and require less lines of code. In biger projects you should consider pinia as more extendable and solution but cookies also have advantages in security area.
Let’s create two variables by useCookie
function.
const token = useCookie('token');
const user = useCookie('user');
now we will watch on data returned from login request
watch(data, (value) => {
token.value = value.jwt;
user.value = value.user;
})
our useLazyFetch
result is now extended by execute
const {data, error, execute, pending} = await useLazyFetch...
so login function can be rewritten
function login() {
if(JSON.stringify(requestBody.value) === JSON.stringify(formBody.value)) {
execute()
} else {
requestBody.value = formBody.value;
}
}
this change allow to execute login many times with she same payload.
It is especially important to avoid bugs, because we now added also logout
function
function logout() {
token.value = '';
user.value = '';
}
In template we added token
and v-if
to display login form for not logged in and logout button for logged in users.
<template>
<div>
<pre>{{ token }}</pre>
<hr>
<pre>PENDING: {{ pending }}</pre>
<pre>DATA: {{ data }}</pre>
<pre>ERROR: {{ error }}</pre>
<hr>
<div v-if="token">
<pre>{{user}}</pre>
<button @click="logout">Logout</button>
</div>
<div v-else>
<form @submit.prevent="login">
<label for="email">
Email
<input type="text" v-model.lazy="formBody.identifier">
</label>
<label for="password">
Password
<input type="password" v-model.lazy="formBody.password">
</label>
<button>Login</button>
</form>
</div>
</div>
</template>
We can now create second page
npx nuxi add page profile
and in script get user and router and then decide if we need to redirect to login
import {useCookie, useRouter} from "#imports";
const user = useCookie('user');
const router = useRouter();
if(!user.value) {
router.push('/login');
}
our symbolic template can have form
<template>
<div v-if="user">
<p>Email: {{user.email}}</p>
</div>
</template>
That’s it. We built super simple front with login and profile pages. There is no styling, no registration and even I skipped part with strapi setup. But thanks to these simplifications it is useful as base to speedup setting up new nuxt3 projects. I hope it will be useful for you and help to avoid situations like on image below:
Other articles
You can find interesting also.
Scraping of the Pharmacy Register
Data administrators hate it. See how by entering two commands in the console he downloaded the register of all pharmacies in Poland.
Daniel Gustaw
• 7 min read
Calculating the Difference Between JSON Files
Learn how to find missing translations in JSON files with dictionaries.
Daniel Gustaw
• 3 min read
How many families can fit on the plane - an algorithmics problem
We compare two solutions to the problem of counting free sets of adjacent seats. You will learn how to use Profiling and how much difference the use of pop and shift makes on arrays in js.
Daniel Gustaw
• 12 min read