Having hit the ground running with SvelteKit by building our project's layout as well as its logout feature in the previous article, we'll continue exploring SvelteKit in this article by implementing login and registration features.
Source code
The overall source code for this project can be accessed here:
This project was deployed on heroku (backend) and vercel (frontend) and its live version can be accessed here.
To run this application locally, you need to run both the backend and frontend projects. While the latter has some instructions already for spinning it up, the former can be spinned up following the instructions below.
This project was deployed on heroku (backend) and vercel (frontend) and its live version can be accessed here.
Step 1: Implement the login functionality
Let's begin by implementing the login functionality of our app. Open up routes/accounts/login/index.svelte in your editor and make the content look like:
This .svelte file contains a couple of new imports and some scripts aside the notificationData explained in the previous article. The first notable import is post. This abstracts away sending POST requests to the server and has the following definition in lib/requestUtils.ts:
It is an asynchronous function which expects the global window.fetch, the url to send the request, and the data to be sent. Looking into the try block, we enforced that only json data type will be handled and then went on to make the post request while ensuring proper error handling from the response.
Back to the .svelte file, we declared some variables — email, and password — and bound them to their respective form inputs using the bind:value directive. A very simple and intuitive way of binding input values without the ceremonial state bindings in react. To give feedbacks about possible errors, we also have the error variable declared which later on was given the error response from the post function.
Entering the handleLogin asynchronous function, we first remove any residual refreshToken that might lurking around user's browser. If not done, we will be faced with some non-informative error if the user tries to login. Then we called on our post function and passed in the required arguments. If no errors was encountered, we save the user's refeshToken to localStorage, update the notoficationData and redirects the user to the home page. The handleLogin function was called on the form's submission using the on:submit directive. Notice that before assigning this directive to the function, we added |preventDefault. This is extremely important to prevent full page refresh which defeats app-like feel.
Since users are automatically redirected to the login page after logging out of their accounts, we also implemented a simple way of resetting the notificationData and animating the notification via the setTimeout function located inside onMount. onMount is almost equivalent to react's componentDidMount lifecycle. The reason setTimeout was put inside this lifecycle is too ensure that the page has fully been loaded and we have access to document.getElementsByClassName('notification');.
Step 2: Implement the registration flow:
Now that we've gone through how the login was implemented, let's checkout the registration flow. In the routes/accounts/register/index.svelte, we have the snippets below:
We did same thing as what we did with the login flow aside from using different api endpoint, updating notificationData to a different string, sending more data to the server, and redirecting to the login page. Also, we didn't use our post function here but using it should produce same output.
That's basically it! We have successfully implemented a robust full stack jwt authentication system! Though we have done some authorizations as well but not intentional enough. We will try to do some intentional authorizations in our bonus article where we'll look into how to update user data and maybe create an endpoint which only users with admin role can assess and manipulate its data! Please, be on a lookup for it!!!