t sriyaLogout, Deployment & Lessons Learned Over the previous articles, we built a complete...
Over the previous articles, we built a complete authentication system from scratch.
We implemented:
At this stage, the authentication system is fully functional. However, one important piece is still missing—logging the user out securely.
In this final part, we'll implement the logout flow, deploy the application to production, discuss the challenges encountered during deployment, and summarize the key learnings from the entire project.
Logging out isn't just about redirecting the user back to the login page.
In applications that use JWT authentication, the client may still possess valid authentication tokens. If those tokens remain active after logout, they could potentially be reused until they expire.
A secure logout process ensures that the user's session is completely terminated and prevents the generation of new access tokens.
The logout process is shown below.
User clicks Logout
│
▼
Frontend sends Logout Request
│
▼
Backend authenticates User
│
▼
Invalidate Refresh Token
│
▼
Return Success Response
│
▼
Frontend clears Authentication State
│
▼
Redirect to Login
Unlike login, logout does not require the user to provide credentials. Instead, the request is authenticated using the existing access token.
The logout request first passes through the authentication middleware, which verifies the access token and identifies the currently logged-in user.
Once the user is authenticated, the backend removes the stored refresh token from the database.
By invalidating the refresh token, the application prevents future access token generation, even if the old access token has not yet expired.
const logout = async (req, res) => {
try {
const userId = req.user.id;
const result = await authService.logout(userId);
return res.status(200).json(result);
} catch (err) {
return res.status(400).json({
success: false,
message: err.message,
});
}
};
The repository performs the database operation required for logout.
Its responsibility is simply to clear the refresh token stored against the authenticated user.
const updatePassword = async (password_hash, id) => {
await pool.query(
`UPDATE users SET reset_token= $1, reset_token_expiry =$2, password_hash =$3 where id= $4`,
[null, null, password_hash, id]
);
};
Keeping this logic inside the repository maintains the same clean architecture used throughout the project.
After receiving a successful response from the backend, the frontend clears all authentication-related data.
This includes:
Once the application state is cleared, the user is redirected to the login page.
This ensures that protected routes are no longer accessible.
With all authentication features complete, the next step was deploying the application.
I chose the following platforms:
| Application | Platform |
|---|---|
| Frontend | Vercel |
| Backend | Render |
| Database | PostgreSQL |
This setup closely resembles how many real-world applications are deployed.
The backend was deployed to Render.
Deployment required configuring several environment variables, including:
One important lesson I learned is that environment variables are never deployed automatically from the local .env file.
They must be manually added through the Render dashboard.
The React application was deployed using Vercel.
Since this is a Single Page Application (SPA), client-side routing required additional configuration.
Without proper routing configuration, directly visiting URLs such as:
/auth/reset-password/:token
resulted in:
404 NOT FOUND
Configuring Vercel to redirect all requests to index.html resolved the issue and allowed React Router to handle client-side navigation correctly.
Building the authentication system was only part of the journey. Deploying it introduced several real-world challenges.
Some of the issues I encountered included:
Initially, I used Nodemailer with Gmail SMTP.
While it worked perfectly in the local environment, the deployed backend on Render consistently failed with IPv6 connection errors.
After investigating the issue, I migrated to Resend, which provided a much simpler and more reliable solution for transactional emails.
During deployment, the backend repeatedly failed because required environment variables had not been configured on Render.
Although the application worked locally, production deployments require all secrets to be added manually through the hosting platform.
This reinforced the importance of understanding environment management.
Password reset links worked locally but returned 404 errors after deployment.
The issue turned out to be related to Vercel's handling of React Router.
Configuring proper SPA rewrites fixed the problem.
Since the frontend and backend were deployed on different domains, proper CORS configuration became essential.
Restricting requests to only trusted frontend origins ensured secure communication between the client and server.
Building this authentication system taught me much more than implementing login and registration.
Some of the biggest takeaways include:
More importantly, I learned that building software isn't just about writing code—it's equally about understanding architecture, security, debugging, deployment, and real-world problem solving.
Authentication is one of the foundational building blocks of modern web applications.
While libraries and third-party authentication providers make implementation easier, building the entire authentication flow from scratch provides a much deeper understanding of how these systems work internally.
This project helped me understand not only authentication but also backend architecture, API design, database interactions, deployment strategies, and security best practices.
Although there are many possible enhancements—such as email verification, role-based access control, OAuth login, Redis token blacklisting, and multi-factor authentication—the current implementation already provides a strong, production-ready authentication foundation.
I hope this series helps anyone looking to understand authentication beyond simply copying code from tutorials.
Live App: https://auth-flow-five-iota.vercel.app/auth/
Backend API: https://auth-flow-backend-1v2h.onrender.com/
github url: https://github.com/sriyaT/Auth-Flow
Connect : LinkedIn : https://www.linkedin.com/in/t-sriya-b4234510a/, github : https://github.com/sriyaT
Happy Coding! 🚀
Author: Sriya T.