In this article, I will demonstrate how to authenticate the Qwik web application using a Laravel-powered API backend. Before you proceed ensure that your Laravel API backend is ready for SPA authentication. I covered that in Preparing a Laravel API backend for SPA authentication using Sanctum. The following video show what we will be building.
What is Qwik
Qwik is a JavaScript framework that solves problems other frameworks can't solve. To truly appreciate Qwik's uniqueness, it's important to understand the shortcomings of current frameworks, which is hydration. With hydration, the frameworks must download all component code linked to the current page and execute associated templates to rebuild listener locations and internal components. Hydration is, therefore, expensive.
Qwik, on the other hand, uses no hydration and rather uses a technique known as Resumability. Qwik app serialises a page into HTML, pauses execution on the server, and the application can resume execution on the client without having to replay and re-download. Qwik apps have instant-on startup performance. They also have the same initial javascript regardless of the complexity of the application.
With Qwik, you can build applications that are instantly interactive, fast, and scalable - all with Developer Experience like that of React or Vue. You can learn more from the Qwik website.
Why not Just use Auth.js
Auth.js is an open-source authentication solution for web applications. Auth.js eliminated the complexity of authenticating with OAuth providers, databases, and email magic links, among others. While the library is great and has Qwik support, it has poor support for credentials authentication (username and password) and does not play well with Laravel.
My first attempt was to generate a Sanctum API token and store it in an Auth.js JSON Web Token (JWT) encrypted cookie. I also implemented session-based authentication using Auth.js. Both methods proved futile. User experience (UX), when credentials failed, could have been better; there was no fluent way of authenticating users after registration. I
I ended up going the vanilla way of authentication, and that is what I will cover in this article.
Install new qwik application
Install a new empty qwik application, if you do not have one already
Create vite environment variables
Then add the following public build-time variables.
Note: PUBLIC_API_ENDPOINT MUST match Laravel APP_URL while PUBLIC_SESSION_NAME MUST match Laravel SESSION_NAME. The variables are prefixed with PUBLIC_ so that we can access their value from the client side (browser).
Install modular form and valibot
Modular Forms is a type-safe Javascript form library that we will use to build our login form.
Next we add Validbot a type safe type safe data validation. We will use Validbot to minimise hits on out API endpoint
Install Tailwindcss (optional)
Tailwind is a CSS framework that will help up add basic styles to our login page. Tailwindcss is optional and you can use any other framework.
Add login page
Create a new login route in your Qwik application by running the following command
Form here we are going to edit src/routes/login/index.tsx.Start by importing the api Laravel API endpoint to the client (browser).
Define the login form. The schema should include the error messages you wish to show your users.
You can add more fields in the scheme if required. Next, set the initial value of the login form and link the validation.
Next, import useNavigation we will use it to re-direct the user once authenticated.
You should now be having a styled form that can validate input using the rules we specified.
Add login functionality
When you submit the form the values are validated and passed to handleSubmit function we created. First We need to make a GET request to the ${endpoint}/sanctum/csrf-cookie endpoint to initialize CSRF protection for the application. Since we will user fetch in favour of axios, we enable { credentials: 'include' } to ensure the XSRF-TOKEN received from Laravel is saved in the browser cookies.
We then read the value of XSRF-TOKEN from the browser using the helper function getBrowserCookieValue
If the sanctum/csrf-cookie request was successful, token should now have a the value of XSRF-TOKEN similar to this example below
Next we make a POST request to ${endpoint}/login attaching the token as X-XSRF-TOKEN header. We also submit the values of email and password in the request.
if the response is successful, we re-direct the user to the intended page, e.g dashboard.
If the response fails with 422, we display Laravel validation errors in the form. You can handle the rest of the errors as you deem fit.
Final login form
We get a functional login form if we put all the building blocks together.
Adding authentication middleware
It is a common practice to secure some page such that they are only accessible to authenticated user. To implement this feature in Qwik, we need a middleware that check if the user is authenticated in every request. Create a new file at src/routes/[email protected] and add the following content.
What is going on here?
We read XSRF-TOKEN value from the cookie passed from the browser. We also read the cookie value for the laravel session that matches the session_name.
If both cookie values are not undefined or null, the the user is like to be authenticated.
We make a POST request to ${endpoint}/api/user to get the authenticated user. In the request, we attach XSRF-TOKEN as X-XSRF-TOKEN header, origin header and we attached laravel cookie. If we MUST include the three headers, else the request will return 401.
If the response form Laravel is successful, we store the user in the sharedMap. Data stored in sharedMap is accessible in the HTTP request. You can learn more about shared map from Qwik documentation
Securing dashboard
Let us add a dashboard route that is only accessible in to authenticated user.
We then add a middleware that check is there is a user in sharedMap. If not, we redirect the guest to login page.
The useUser is a re-usable function placed in the src/routes/layout.tsx that get the user from sharedMap
Conclusion
By now you should be able to implement other authentication requirements such as logout and registration. The source code for both the Laravel API and Qwik app is available on Github
Common errors
You are getting 401 unauthenticated error even after successful login. Solution: Ensure your laravel SANCTUM_STATEFUL_DOMAINS include you frontend e.g SANCTUM_STATEFUL_DOMAINS=localhost:5173