This tutorial is part of the « E-commerce website with Strapi, Nuxt.js, GraphQL and Strip »
Note: The source code is available on Github.
At this point, you may have expected to get ready to order. But before that, you need to give the user the possibility to register and log in to your app. No worries, Strapi comes to the rescue with its Users & Permissions plugin already installed in your project.
In this article, you will create a new user system. With the ability to verify, create, and logout a user.
To quicken your front-end development, you are going to install an HTTP module. HTTP module for Nuxt.js provides a universal way to make HTTP requests to our Strapi API.
Let’s add @nuxt/http
dependency to our project:
1 npm install @nuxt/http
Then add it to the modules section in your nuxt.config.js
:
1 // nuxt.config.js
2 const strapiBaseUri = process.env.API_URL || 'http://localhost:1337'
3
4 export default {
5 // Modules: https://go.nuxtjs.dev/config-modules
6 modules: ['@nuxt/http', '@nuxtjs/apollo'],
7
8 // nuxt/http https://http.nuxtjs.org/API/options
9 http: {
10 baseURL: `${strapiBaseUri}/api`,
11 browserBaseURL: `${strapiBaseUri}/api`,
12 },
13 }
Create a new store named auth.js
and copy/paste the following code:
1 // store/auth.js
2 import Cookies from 'js-cookie'
3
4 export const state = () => ({
5 user: {},
6 })
7
8 export const mutations = {
9 setUser(state, user) {
10 state.user = user
11 Cookies.set('user', JSON.stringify(user))
12 },
13 logout(state) {
14 state.user = null
15 Cookies.set('user', null)
16 },
17 }
18
19 export const getters = {
20 user: (state) => {
21 return state.user?.id
22 },
23 username: (state) => {
24 return state.user?.username
25 },
26 token: (state) => {
27 return state.user?.jwt
28 },
29 }
The newly created store, will store user information (id, username, and a JWT
which lets your users request your API as an authenticated one).
To make sure the user stay connected even after page reload, you will also use cookies. Create a new index.js
file inside your store
directory, and define a new nuxtServerInit
function:
1 // store/index.js
2 import cookieparser from 'cookieparser'
3
4 export const actions = {
5 nuxtServerInit({ commit }, { req }) {
6 if (req && req.headers && req.headers.cookie) {
7 const parsed = cookieparser.parse(req.headers.cookie)
8 const user = (parsed.user && JSON.parse(parsed.user)) || null
9 const cart = (parsed.cart && JSON.parse(parsed.cart)) || []
10 commit('auth/setUser', user)
11 commit('cart/setItems', cart)
12 }
13 },
14 }
Since user sessions is defined and stored in the server, we can only access it through req.headers.cookie
. To add the authenticated user to our store, we parse browser cookies in page.
Now, let's create a registration page. Create a new auth
directory inside your pages
directory. Then create a new file register.vue
inside the new auth
directory.
1 // pages/auth/register.vue
2 <template>
3 <div class="uk-container uk-container-xsmall">
4 <h1 class="uk-heading-xsmall uk-margin-top">Sign up</h1>
5 <form @submit.stop.prevent="handleSubmit">
6 <div v-if="err" class="uk-alert-danger" uk-alert>
7 <a class="uk-alert-close" uk-close></a>
8 <p>{{ err.message }}</p>
9 </div>
10 <div class="uk-margin">
11 <label class="uk-form-label">
12 Username
13 <input v-model="username" class="uk-input" type="text" />
14 </label>
15 </div>
16 <div class="uk-margin">
17 <label class="uk-form-label">
18 Email
19 <input v-model="email" class="uk-input" type="email" />
20 </label>
21 </div>
22 <div class="uk-margin">
23 <label class="uk-form-label">
24 Password
25 <input v-model="password" class="uk-input" type="password" />
26 </label>
27 </div>
28 <button class="uk-button uk-button-primary uk-width-1-1" type="submit">
29 Register
30 </button>
31 </form>
32 </div>
33 </template>
34 <script>
35 import { mapMutations } from 'vuex'
36 export default {
37 data() {
38 return {
39 username: '',
40 email: '',
41 password: '',
42 err: null,
43 }
44 },
45 methods: {
46 // Method that will register your users
47 async handleSubmit() {
48 try {
49 const { jwt, user } = await this.$http.$post('auth/local/register', {
50 username: this.username,
51 email: this.email,
52 password: this.password,
53 })
54 this.setUser({
55 jwt,
56 id: user.id,
57 username: user.username,
58 })
59 this.$router.push({
60 path: '/',
61 })
62 } catch (err) {
63 this.err = err.response?.data?.error
64 }
65 },
66 ...mapMutations({
67 setUser: 'auth/setUser',
68 }),
69 },
70 }
71 </script>
In this page, you display a form which has three inputs: username, email and password. You also defined a method named handleSubmit
which uses the REST API to register the user before redirecting them to the home page.
Perfect! You are going to create a sign in page right now. Create a new login.vue
file inside your auth
directory.
1 // pages/auth/login.vue
2 <template>
3 <div class="uk-container uk-container-xsmall">
4 <h1 class="uk-heading-xsmall uk-margin-top">Log In</h1>
5 <form @submit.stop.prevent="handleSubmit">
6 <div v-if="err" class="uk-alert-danger" uk-alert>
7 <a class="uk-alert-close" uk-close></a>
8 <p>{{ err.message }}</p>
9 </div>
10 <div class="uk-margin">
11 <label class="uk-form-label">
12 Email
13 <input v-model="email" class="uk-input" type="email" />
14 </label>
15 </div>
16 <div class="uk-margin">
17 <label class="uk-form-label">
18 Password
19 <input v-model="password" class="uk-input" type="password" />
20 </label>
21 </div>
22 <button class="uk-button uk-button-primary uk-width-1-1" type="submit">
23 Log In
24 </button>
25 </form>
26 </div>
27 </template>
28 <script>
29 import { mapMutations } from 'vuex'
30 export default {
31 data() {
32 return {
33 email: '',
34 password: '',
35 err: null,
36 }
37 },
38 methods: {
39 async handleSubmit() {
40 try {
41 const { jwt, user } = await this.$http.$post('auth/local', {
42 identifier: this.email,
43 password: this.password,
44 })
45 this.setUser({
46 jwt,
47 id: user.id,
48 username: user.username,
49 })
50 this.$router.push({
51 path: '/',
52 })
53 } catch (err) {
54 this.err = err.response?.data?.error
55 }
56 },
57 ...mapMutations({
58 setUser: 'auth/setUser',
59 }),
60 },
61 }
62 </script>
In this page, you display another form which has only two inputs: username and password. You also defined handleSubmit
method which uses the REST API to vertify the user before redirecting them to the home page.
Create a new Header.vue
component in components
directory.
1 // components/Header.vue
2 <template>
3 <nav class="uk-navbar uk-navbar-container" uk-navbar>
4 <div class="uk-navbar-left">
5 <NuxtLink class="uk-navbar-item uk-logo" to="/">Deliveroo clone</NuxtLink>
6 </div>
7 <div class="uk-navbar-right">
8 <ul v-if="username" class="uk-navbar-nav">
9 <li>
10 <button class="uk-button uk-button-link uk-navbar-toggle">
11 Shopping Cart
12 <span v-if="numberOfItems" class="uk-badge">{{
13 numberOfItems
14 }}</span>
15 </button>
16 <div class="uk-navbar-dropdown">
17 <Cart />
18 </div>
19 </li>
20 <li>
21 <button
22 class="uk-button uk-button-link uk-navbar-toggle"
23 @click="logout"
24 >
25 Log out
26 </button>
27 </li>
28 </ul>
29 <ul v-else class="uk-navbar-nav">
30 <li><NuxtLink to="/auth/login">Log In</NuxtLink></li>
31 <li><NuxtLink to="/auth/register">Register</NuxtLink></li>
32 </ul>
33 </div>
34 </nav>
35 </template>
36 <script>
37 import { mapGetters, mapMutations } from 'vuex'
38 export default {
39 computed: {
40 ...mapGetters({
41 username: 'auth/username',
42 numberOfItems: 'cart/numberOfItems',
43 }),
44 },
45 methods: {
46 ...mapMutations({
47 logout: 'auth/logout',
48 }),
49 },
50 }
51 </script>
Using the <NuxtLink>
component, we create a new link to the home inside our Header component.
The header is a standalone component, which we will display on every page. It contains the login, logout and sign-up buttons. It also shows the shopping car, a dropdown which display a list of selected dishes, the sum and a checkout button.
Next we will extend the main layout by adding a layouts/default.vue
file. It will be used for all pages.
Create a new folder layouts
, we will use the <Nuxt>
component to include the page component, check Layouts directory for more informations.
Next, create a new file layouts``/default.vue
and then copy/paste the following code.
1 <template>
2 <div>
3 <Header />
4 <nuxt />
5 </div>
6 </template>
Reload your page and play with this new user system you just created! or try navigation to the following links:
That's it for the authentication! You will now have a Log In, Register, and Log Out links in your page header. 💵 In the next section, you will learn how to set up Stripe for checkout and create orders.
Pierre created Strapi with Aurélien and Jim back in 2015. He's a strong believer in open-source, remote and people-first organizations. You can also find him regularly windsurfing or mountain-biking!