Introduction to Nuxt.js and Laravel
Nuxt.js is a framework for building Jamstack websites that are super fast and super SEO friendly. It's built on the top of the great Vue JavaScript framework.
Nuxt.js can be perfectly combined with any kind of back end, and that includes Laravel back ends. In this video, we are going to use Nuxt.js to build a front end that interacts with the Laravel REST API to authenticate users and fetch data.
The back end we are going to use the ergodnc app that we built earlier during several live streams. I will leave links to the stream and the final code in the description down below.
Project Setup Overview
So let's get to it, but first, let me show you what I've already prepared off-camera.
I have created a Nuxt.js app using the current stable version, which is version 2 at the time of making this video. During the installation, I chose to install Tailwind CSS and Axios. If you are not familiar with Axios, it is a promise-based JavaScript HTTP client that we will use to interact with our Laravel API.
Inside the Nuxt.js app, I have created several components for buttons, input fields, labels, and error messages. I've also created several pages with some basic Tailwind CSS styling: one page for the index, one page for the login page, one page for the profile page, and one for showing a single entry.
All these pages currently have dummy static HTML that's not reading from the REST API yet. Now let's get our Nuxt.js server up and running by running npm run dev. Once the server is up and running, we will visit localhost:3000 to view our front end.
The REST API, on the other hand, is hosted on the local ergodnc.test domain that is served via Laravel Valet.
Local Domain Configuration with Valet
What we want to achieve here is to be able to communicate with our REST API via Sanctum session-based authentication. This Nuxt.js app is a first-party front-end for the ergodnc app, which means it will be hosted on the same domain as the API. And because of that, we will be able to use session-based authentication to authenticate users of our front end on our Laravel back end. Session-based authentication provides the benefits of CSRF protection as well as protects against the leakage of authentication credentials via XSS.
Now, to be able to test our session authentication locally, we need both the Nuxt.js and the Laravel app to share the same domain. So we are going to use Valet's link and proxy commands to serve the back end on api.ergodnc.test and the front-end on app.ergodnc.test. To do that, we will run valet link api.ergodnc from within the ergodnc directory, and then run valet proxy and provide app.ergodnc for the domain and http://127.0.0.1:3000 for the host.
Laravel Back-End Configuration for Sanctum
Now if we visit api.ergodnc, we will see our Laravel app, and if we visit app.ergodnc.test, we will see our Nuxt.js app. To ensure the session cookie is shared between the two subdomains, we are going to configure the session domain environment variable in the Laravel app to .ergodnc.test. We will also configure the Sanctum stateful domains variable to add app.ergodnc.test to Sanctum's stateful domains, so it applies the session middleware to requests coming from the origin.
Finally, we will update the cors.php configuration file and set supports_credentials to true to set the Access-Control-Allow-Credentials header on requests, and also change the accepted paths to all paths since the entire Laravel app here is an API app.
Nuxt.js Axios Configuration
On the Nuxt.js app side, we need to configure Axios a little bit. So we will head to the nuxt.config.js file and update the axios attribute. We will set credentials to true to include cookies with every request and configure the baseURL to http://api.ergodnc.test, which is where our Laravel API is hosted.
Fetching & Displaying a List of Records
And now we have everything ready to start working on the Nuxt.js app. So let's do just that and work on the index.js file to display the list of records from the API. All we need to do is add a fetch hook inside the script section of our Vue page, and inside the function, we will use the Axios plugin we have configured to send a request to the offices endpoint. Notice that we use await to wait for the promise to resolve. Then, we will use the response data to mutate the offices property. And now we are ready to remove the dummy offices values and provide an empty array as the default value.
Finally, let's use fetchState to show a loading indicator if the data fetching is still pending and an error message if it encounters an error. We will then wrap our markup inside a template that will be rendered if the fetch state is successful. And now let's visit the app in the browser, and we can see that it is reading from our Laravel API. No dummy data anymore.
Fetching & Displaying a Single Record
Let's implement another page, which is the page for showing a single office. We will add a fetch hook inside the script section of our Vue page. Inside the function, we will use the Axios plugin we have configured to send a request to the offices endpoint to print the requested office resource. Notice we can read the URL parameters from the route parameter here.
Next, we will use the response data to mutate the office property and remove the dummy office data. And finally, we will use fetchState to render a loading view or an error view like what we did in the previous page.
Installing and Configuring Nuxt/Auth
And now let's visit one of the office pages in the browser and here we go. We can see that it is displaying the correct office data. Perfect. Let's get to working on the login screen.
For starters, we will install the Nuxt.js, or the auth-next module by running npm install @nuxtjs/auth-next. After that, we will add it to the modules attribute inside nuxt.config.js. We will also add an auth attribute inside the file to configure the auth module. So first, we will add a strategies attribute that configures the cookie strategy, since we are using cookie authentication in this app. We will need to configure four endpoints: one for initializing CSRF protection—this one points to sanctum/csrf-cookie since we are using Laravel Sanctum in our Laravel API. The other three endpoints are for the login route, the logout route, and the user route. Nuxt/Auth will use this user route to get the current logged-in user after authentication.
And since we are using JSON resources to build responses in our Laravel app, we need to configure the property Nuxt/Auth will use to extract the user data from the response of the user endpoint. In our case, that will be the data attribute.
Configuring Auth Redirects and Plugins
Now we will configure several redirects: when Nuxt.js wants to redirect to the login page, where to redirect after logout, and where to redirect when the user visits the login page while they are already authenticated. Finally, we will configure a plugins attribute and point it to an axios file inside the plugin directory. Setting this attribute will make the auth module available inside the Axios plugin extension that we will just create now.
We will create a directory called plugins in the root of our project and inside that directory, we will create an axios.js file. Inside the file, we will export a function that uses the axios parameter to intercept errors on any requests made by Axios and check if the response code was 401. In that case, we will log the user out and redirect them to the login page. That way, if the user session expires, we will be able to catch the 401 response coming from the Laravel app and log the user out of our Nuxt.js app.
Activating Vuex and Reviewing the Laravel Backend
One more thing: we need to create an index.js file inside the store directory so Nuxt.js activates the Vuex store, which is needed by the Nuxt/Auth module.
Now the Nuxt.js app is ready to authenticate users and protect pages that require authentication from unauthenticated access. Before we implement the login page, let's take a look at the Laravel app. The login endpoint in the Laravel app uses the fromFrontend method of the EnsureFrontendRequestsAreStateful class to check if the request is coming from our front-end. In that case, we will authenticate using the web guard, otherwise, we may use token authentication.
The logout endpoint also makes the same check and uses the web guard to invalidate the session, otherwise, we may revoke the token.
Right, now that the Nuxt.js app and the Laravel app are both ready, we will work on implementing the login page by utilizing functions provided by the Nuxt/Auth module. Inside the login page, we will add a submitForm function. Inside this function, we will reset the errors data parameter before we attempt authenticating the user. Then we use the $auth helper provided by the Nuxt/Auth module to call the loginWith function and provide the cookie strategy as the first parameter, and the form data as the second parameter. If the authentication succeeds, we will redirect the user to the home page; otherwise, we will populate the errors property with errors coming from the API.
Now let's head to the browser and view the login page. Let's first try to log in with wrong credentials, and we will see the incoming validation errors displayed in the form. Now let's log in with valid credentials, and we can see that we get redirected to the home page.
Updating the UI and Implementing Logout
How will the user know the authentication was successful? Well, let's change this part in the header and display links to log out and view the user profile. To do that, let's head to the default layout file and use the $auth helper to extract the user object. We will use this object to check if there is a user and display the profile and logout links; otherwise, we will display the sign-in and create account links.
For the logout link, we will call the logout function when the link is clicked. Finally, we will implement the logout function by calling the logout function on the $auth helper. Now let's head to the browser and see what we have. We can see that the logout and profile links are displayed because the user is logged in. If we click logout, we will get redirected to the login page and the header links will change back to sign in and create account because we are now logged out.
Protecting Routes with Middleware
Alright, looking in and out seems very easy. Let's look into one more thing, which is redirecting the user to the root page if they visit the login page while they are already logged in. Doing that with Auth, or using the Nuxt/Auth module is very easy. All we have to do is add a middleware attribute to the login page and set it to auth, and then add an auth attribute and set it to guest.
Now if we check in the browser while being authenticated, the login page will redirect us to the root page. I told you that it's pretty easy. Kudos to the contributors and maintainers of Nuxt.js and Nuxt/Auth for making this so easy.
Creating a Protected Profile Page
Alright, let's move to work on the profile page. For this page, we will use the fetch hook to read the reservations from the reservations endpoint and assign the results to the reservations data property. We will also use fetchState to display a loader or an error message when needed. Then let's add a middleware attribute to apply the auth middleware. If an unauthenticated user tries to open this page, they will get redirected to the login page.
Now we get rid of the dummy reservations here. Let's check everything in the browser. Make sure we are authenticated and then head to the profile page, and here we go. We can see that it was able to read the logged-in user's name and reservations. Now let's log out and then revisit the profile page, and we get redirected to the login page.
Conclusion and Next Steps
And that's it! We have our Nuxt.js app communicating with our Laravel app and authenticating via session-based authentication. I'm going to leave links to the code of the Nuxt.js app and the Laravel app in the description down below.
Also, I've made a video on building the same front end we built today using Next.js, the React framework. Check it out if you want to compare between the two frameworks. Finally, the team behind Nuxt is currently working on version 3, which will support Vite, Vue 3, incremental static generation, and more. Check the website for the beta version to learn about the new features and follow the progress.
And that's all I have for you today. I hope you learned something and I hope to see you soon in the next video. Goodbye.