Hey there! It's October, the season of open-source applications. Recently, I was building a product similar to dub.co, the app that lets you shorten and manage your web links. I created the application, and below is an early version of it. Take a look!
Here's an early version of the product I'm working on. Below is the tech stack I'm using:
Next.js - Full stack framework
Neon - Postgres database on the cloud
Auth - Hanko (I'll show you how I use it)
Prisma - Database ORM
Vercel - Free hosting!
why do you need auth in your SaaS?
As a developer building modern web applications, you know that authentication is a critical piece of the puzzle. Implementing secure and user-friendly authentication can be a time-consuming and complex task. That's where Hanko comes in - a powerful authentication platform that can simplify your development process and provide a seamless experience for your users.
But what is Hanko and why should I use it?
Hanko is an authentication-as-a-service platform that provides a comprehensive set of tools and APIs to handle all your authentication needs. With Hanko, you can easily implement features like password-less login, multi-factor authentication, and social login, without the hassle of building and maintaining these complex systems yourself.
Benefits of Using Hanko
Reduced Development Time: Hanko's pre-built components and APIs allow you to quickly integrate authentication into your application, saving you valuable development time.
Improved Security: Hanko's authentication solutions are built with security in mind, helping you protect your users and their data.
Enhanced User Experience: Hanko's intuitive and customizable authentication flows provide a seamless experience for your users, improving engagement and satisfaction.
Scalability: Hanko's scalable infrastructure can handle authentication needs for applications of all sizes, from small startups to large enterprises.
Integrating Hanko into Your Application
Prerequisites
Before we begin, make sure you have the following:
A Hanko account and API credentials (you can sign up for a free trial at hanko.io)
A web application (we'll use a React-based application in this example)
This is my current directory file structure. I am using the Bun package manager for this project, so if you're following along, you need to install it too. As you can see, I have created a .env file for this. Let's get started.
First, log in to the Hanko cloud to manage your project and get the API keys for authentication. We will use these API keys to access Hanko's built-in components. Below is an image of the dashboard where you can create your project and obtain the key.
First, install the Hanko package. By installing hanko-elements
, you gain access to the prebuilt components: hanko-auth
and hanko-profile
.
bun add @teamhanko/hanko-elements
After the installation is complete, create a .env file in the root directory of your Next.js project. Also, make sure to add the .env file to the .gitignore file to prevent it from being committed to GitHub.
NEXT_PUBLIC_HANKO_API_URL=https://f4****-4802-49ad-8e0b-3d3****ab32.hanko.io
Cool now let’s start adding the auth components to the files.First add create a file in your app directory components and in your components directory create a file called HankoAuth.tsx and add the below code.
"use client";
import { useEffect, useCallback, useState } from "react";
import { useRouter } from "next/navigation";
import { register, Hanko } from "@teamhanko/hanko-elements";
const hankoApi = process.env.NEXT_PUBLIC_HANKO_API_URL;
export default function HankoAuth() {
const router = useRouter();
const [hanko, setHanko] = useState<Hanko>();
useEffect(() => setHanko(new Hanko(hankoApi)), []);
const redirectAfterLogin = useCallback(() => {
router.replace("/dashboard");
}, [router]);
useEffect(
() =>
hanko?.onSessionCreated(() => {
redirectAfterLogin();
}),
[hanko, redirectAfterLogin]
);
useEffect(() => {
register(hankoApi).catch((error) => {
console.log(error)
});
}, []);
return <hanko-auth />;
}
Here we added a Hanko auth web component from the package as well as set up router to redirect when the user is logged in with the redirectAfterLogin function The <hanko-auth>
web component adds a login interface to your app. Begin by importing the register function from @teamhanko/hanko-elements
into your Next.js component. Call it with the Hanko API URL as an argument to register <hanko-auth>
with the browser’s CustomElementRegistry. Once done, include it in your TSX.
The Hanko client from @teamhanko/hanko-elements
allows you to subscribe to specific events. For instance, the onSessionCreated
event here triggers when a user successfully logs in. You can use this event to perform any desired action.
Now we will create a login page where the user can interact by importing the previously created <HankoAuth />
component. it should be in the app/login/page.tsx file.
import HankoAuth from "@/components/HankoAuth";
export default function LoginPage() {
return (
<div className="flex justify-center items-center min-h-screen">
<HankoAuth />
</div>
);
}
After doing this, our sign-up and log-in should be working. However, I need to customize my code a little bit. I created a button using shadcn components, so I need to link it here is the output.
Looks clean, right? If you want to add some styles and customization to the components, you can read the official documentation on Hanko.io. Let's move forward and create a User Profile component so users can manage their email and password keys. Let's do this quickly, thanks to Hanko elements.
"use client"
import { useEffect } from "react";
import { register } from "@teamhanko/hanko-elements";
const hankoApi = process.env.NEXT_PUBLIC_HANKO_API_URL;
export default function HankoProfile() {
useEffect(() => {
register(hankoApi).catch((error) => {
// handle error
});
}, []);
return <hanko-profile />;
}
you can align and style it yourself according to your needs below I have added it on my dashboard.
In the panel, you can see the interface to add other emails, change passwords, create a passkey, and view current session details. You can also create a better interface. Check out the Hanko documentation for more details.
after than we need to create logout component so that the user can navigate to and logout successfully. here you need to create a new component named LogoutButton.tsx or anything you like and add the below code.
"use client";
import { useState, useEffect } from "react";
import { useRouter } from "next/navigation";
import { Hanko } from "@teamhanko/hanko-elements";
const hankoApi = process.env.NEXT_PUBLIC_HANKO_API_URL;
export default function LogoutBtn() {
const router = useRouter();
const [hanko, setHanko] = useState<Hanko>();
useEffect(() => setHanko(new Hanko(hankoApi ?? "")), []);
const logout = async () => {
try {
await hanko?.user.logout();
router.push("/login");
router.refresh();
return;
} catch (error) {
console.error("Error during logout:", error);
}
};
return <button onClick={logout}>Logout</button>;
}
Here will import @teamhanko/hanko-elements
to easily manage user logouts. Below, we make a logout button component that you can use anywhere. I have added it to my dashboard as well.
As you can see, the logout button has been added to my dashboard. It's a crucial part because we need to secure our routes to ensure authentication is active. we will create a middleware.ts file in the root directory of our project and copy the below middleware code and past it.
import { NextResponse, NextRequest } from "next/server";
import { jwtVerify, createRemoteJWKSet } from "jose";
const hankoApiUrl = process.env.NEXT_PUBLIC_HANKO_API_URL;
export async function middleware(req: NextRequest) {
const hanko = req.cookies.get("hanko")?.value;
const JWKS = createRemoteJWKSet(
new URL(`${hankoApiUrl}/.well-known/jwks.json`)
);
try {
const verifiedJWT = await jwtVerify(hanko ?? "", JWKS);
} catch {
return NextResponse.redirect(new URL("/login", req.url));
}
}
export const config = {
matcher: ["/dashboard"],
};
First, you need to install the jose library, which will handle the verification of the JWTs
bun install jose
Once jose is installed, you can create middleware to verify tokens. The middleware intercepts requests to specific routes (e.g., /dashboard) and checks if the user has a valid JWT stored in a cookie.
In this code, we first import NextResponse and NextRequest from Next.js to handle the server-side requests and responses. Then, we use the jwtVerify and createRemoteJWKSet functions from the jose library to verify JWTs. The middleware checks for a hanko cookie, which contains the JWT, and if it finds one, it verifies the token against Hanko’s JWKS. The JWKS is fetched from the URL ${hankoApiUrl}/.well-known/jwks.json, where Hanko provides the public keys to verify the JWT signatures.
If the JWT is valid, the request proceeds. If the token is missing or invalid, the middleware redirects the user to the login page (/login). The matcher configuration ensures that this middleware only applies to the /dashboard route, but you can easily add other routes as needed.
By implementing this middleware, you ensure that only authenticated users can access protected areas of your application, enhancing the security and user experience of your Next.js project.
Everything is now set up, and our application is successfully secured. We've added all these details.
Conclusion
By integrating the Hanko API and Hanko Elements into your web application, you can quickly and securely implement authentication features without the need to build and maintain complex authentication systems yourself. The Hanko platform provides a comprehensive set of tools and APIs to handle all your authentication needs, allowing you to focus on building your core application functionality.
Visit hanko.io to learn more and get started with Hanko today and Don’t forget to like this blog and support it thanks :)