We’ve said it before, and we’ll say it again — everyone loves credentials. Credentials are the glazed donut of data types.
Data Breach Investigations Report
Remember this quote from Verizon's Data Breach Investigations Report (DBIR) every time you want to create a simple password or reuse it. This study has been carried out for the past 14 years. It analyzes thousands of cybercrimes linked to data breaches and provides valuable insights into password security. Cybersecurity specialists harness the power of the following statistics to enhance their systems’ security.
- 74% of website breaches took place because of stolen credentials or brute force attacks.
- Phishing is still one of the most popular means of stealing user data like login credentials or credit cards numbers.
In 2023, 25% of data breaches occurred due to phishing attacks. Stolen credentials caused the lion's share of all data breaches over the past few years.
GoodFirms revealed a new study on Top Password Strengths and Vulnerabilities in 2023. The study attempts to understand the current password behavior of online users as well as password management vulnerabilities. Below are the results obtained from the survey:
- 62.9% of users change their passwords only when prompted
- 30% of users have experienced data breaches due to weak passwords
- 45.7% of users reuse passwords for multiple sites and applications
- 52.9% of users share their passwords with family members, friends, and colleagues
- 35.7% of users still jot down their passwords on sticky notes, paper, or planners
Obviously, most companies know about the main causes of data breaches, and they’re trying to enhance their security systems, but the situation is not getting better from year to year.
We could cite even more studies, but it’s obvious that input field asterisks are causing too many problems for both users and companies.
You may think that the data breach is just a recent problem, but let’s turn back the hands of time. Bill Gates brought up the subject of password vulnerabilities and predicted the death of passwords in 2004. And in 2011, IBM said that passwords would become useless in five years. In 2014, Avivah Litan, VP Analyst at Gartner, expanded on the passwordless argument. In her words, “Passwords were dead a few years ago. Now they are more than dead."
But it's already 2024, and passwords are still the most popular authentication method; they are not going to vanish into thin air. Taking into account all the data above, the human factor is the main cause of data breaches. I think it’s not hard to guess how many data breaches occur due to the human factor, but we know the exact number. According to the DBIR, it's behind 74% of all data breaches.
Today, we're going to explore passwordless authentication methods that can help fix the data breach problem. Let's dive deeper into the issues and find out what passwordless authentication is and how to implement it in software solutions.
What is passwordless authentication?
Passwordless authentication is a means of verifying a user's identity without using a password. Passwords aren't used as an alternative authentication factor or even as a backup. It's an important point to understand since some tech providers say that their authentication is passwordless when they are not.
The idea of passwordless authentication has been on the market for quite a long time. There are now dozens of ways to verify a user’s identity without a password. Two top means of doing so are:
- Biometric authorization (fingerprint, face recognition)
- Certificate-based authentication
However, there are other means that are considered common passwordless authentication methods, but in fact, they are not:
- Magic links
- One-time passwords
These methods aren’t completely passwordless (see more below), but it doesn’t mean they’re bad.
Here's how passwordless authentication works
Every passwordless authentication method follows its unique algorithm. Generally, the system generates two cryptographic keys (one private and one public) when a user signs up to verify their identity. A user keeps a private key, and a public key is stored on the app’s server.
Whenever a user logs in, they need to unlock their private key by performing particular actions like scanning a fingertip. Once the private key is unlocked, the system matches it with the public key. If the key pair is matched, the user is successfully authenticated and can use the app.
Note that the user’s private data never leaves their device. Their fingerprint is only used to unlock the private key.
When speaking about the web, Google and Apple have successfully implemented biometric authentication via a fingertip or Face ID. But those methods haven’t become more popular than magic links. Magic links work similar to the previous method, but they involve an intermediary — an email.
Here’s how magic links work step-by-step:
- A user enters an email address.
- Magic sends an email to the address to verify a user’s identity.
- Once the user’s device or browser is authenticated, private and public keys are generated and stored in the browser. The key pair is generated and stored on the client side in an embedded iframe, and developers cannot access it. Putting it simply, Magic cannot get access to the keys. Instead, the Magic SDK uses a private key to generate a Decentralized ID (DID) token.
DID tokens are cryptographically generated proofs for managing user access to the application’s resource server. Leveraging the Ethereum blockchain, the DID token created by the Magic SDK can generate verifiable proofs of authorization and identity.
These proofs are encoded in a lightweight digital signature that can be shared between server and client to protect routes and resources, manage permissions, and authenticate users. In short, the DID token serves as a user’s digital signature. Once generated, the system sends the token to the server to verify the user. Even if hackers manage to get this token, they will still be unable to get the private key.
Further, this token is passed to the server to verify the user. Magic stores the user's email and id in the browser’s indexedDB. However, some information is stored in cookies and localStorage for accurate and correct performance.
Magic links have just one disadvantage – they are not completely passwordless. So, if a hacker gets access to a user’s email box, they could access the link and get access to the app, platform, or service. There are also ways to secure access to your email, including:
- Enable multi-factor authentication for your email
- Use trusted email providers
Moreover, developers can generate one-time links with an expiration date. Though there are some drawbacks, magic links still work better than any weak or reusable passwords. Hackers cannot leverage phishing attacks or brute force when it comes to magic links. Those attacks just don’t work with magic links. All that users need to do is secure their email boxes.
Pros and cons of passwordless authentication
Eliminates account takeovers from credential attacks
Having watched tons of movies, a vast majority of people imagine hackers as kids skipping school, wearing dark hoodies, and using tons of tech buzzwords. In the real world, they are swindlers who probably have never written something more complex than “Hello, world!” and who are leveraging the power of social computing. Hence, such “hackers” aren’t likely to steal the mathematical representation of fingerprints.
Improves user experience
Using a fingertip scanner or Face ID and entering an email address is easier than remembering hundreds of passwords, looking for a sticker with passwords, or going through the hassle of resetting them.
Saves time and money
Users are likely to forget their passwords, and they do it on a regular basis. 20–50% of all support calls are associated with password resetting.
When resetting a password, no one thinks about how much it can cost a business. On average, a single password reset costs an enterprise up to $70. While estimating the reset cost, we need to consider lots of factors, including the salary of people working in the support center (it’s quite a lot). Some companies have built authentication and authorization infrastructure (AAI), which is both a service and procedure that secures access to protected information distributed on the company’s web servers. In those situations, if an employee forgets their password, they won’t be able to complete their duties. Thus, the employee is wasting their working time while waiting for a password reset. Considering that some users reset their passwords more than 50 times a year, that’s lots of time and resources just pouring down the drain. All in all, enterprises can spend more than a million dollars a year on password resetting support.
Along with benefits, there are some drawbacks of passwordless authentication to consider:
- High cost to implement an enterprise-wide passwordless authentication
- Technical issues connected with the loss of devices or access to an email box
Top considerations for implementing passwordless authentication
This is the point when we need to shift from a theoretical view to a practical one. Jumping ahead a bit, we’re going to discuss how to implement passwordless authentication via magic links. It’s probably the easiest way to implement passwordless authentication.
Today, we’re going to talk about how to create two pages: one for sign-in/login and the other for a homepage (only for logged-in users).
I am going to leverage NextJS, but you can use any framework you like. There won’t be anything complicated.
Let’s start and generate a project: npx create-next-app magic
.
While the project is being generated, we need to head over to https://magic.link/ and press Get started. You need to sign up then. Right after signing up, you’ll be automatically redirected to the dashboard. There are lots of tabs on the left, but you just need the API key from the Home tab. Just copy it and go back to your project.
Set up the needed dependencies:
npm i magic-sdk
or yarn add magic-sdk
Add the API key you copied before to the environment variables. Create a file .env in the root folder and write the following code there:
NEXT_PUBLIC_MAGIC_API_KEY=your API key
Note, that you need to add particle NEXT_PUBLIC
in NextJS. Otherwise, it won’t be defined.
Then, we need to create a new file, lib/magic.js
:
import { Magic } from 'magic-sdk';
const createMagicClient = () => {
return (
typeof window !== 'undefined' &&
new Magic(process.env.NEXT_PUBLIC_MAGIC_API_KEY)
)
}
export const magic = createMagicClient();
You still need to do some routine work to let the magic of passwordless authentication happen. Create two pages:
1. Login page pages/login/index.js
, a simple form for entering an email address.
2. A homepage pages/index.js
, which is only for logged-in users and will display a user’s email address.
Here is the code for a login page:
return (
<div>
<Head>
<title>Login</title>
</Head>
<div className="min-h-full flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8">
<div className="max-w-xs w-full space-y-8">
<div className='flex flex-col'>
<Image
height={100}
width={100}
className="mx-auto h-12 w-auto"
src="https://tailwindui.com/img/logos/workflow-mark-indigo-600.svg"
alt="Workflow"
/>
<h2 className="mt-6 text-center text-3xl font-extrabold text-gray-900">
Sign in to your account
</h2>
</div>
<form className="mt-8 space-y-6" onSubmit={submitHandler}>
<div className="rounded-md shadow-sm -space-y-px">
<div>
<input
type="email"
required
onChange={changeHandler}
className="
appearance-none rounded-none
relative block w-full
px-3 py-2 border
border-gray-300
placeholder-gray-500
text-gray-900 rounded-t-md
focus:outline-none
focus:ring-indigo-500
focus:border-indigo-500
focus:z-10 sm:text-sm"
placeholder="Email address"
/>
</div>
</div>
<div>
<button
type="submit"
className="
group relative w-full flex justify-center py-2 px-4 border border-transparent
text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700
focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500
"
>
<span className="absolute left-0 inset-y-0 flex items-center pl-3"></span>
Sign in
</button>
</div>
</form>
</div>
</div>
</div>
);
There is no need to write CSS on our own. It’s better to leverage Tailwind.
And here is the logic that the component executes:
const [email, setEmail] = useState('');
const router = useRouter();
const changeHandler = (event) => {
setEmail(event.target.value);
};
const submitHandler = async (event) => {
event.preventDefault();
try {
const didToken = await magic.auth.loginWithMagicLink({ email });
if (didToken) router.push('/');
} catch (error) {
console.error(error);
}
};
Let’s get back to the browser and go to localhost:3000/login
.
And now, if you enter your email address in the input field and click on the Sign in button, you will see this:
After clicking on the button, you have 15 minutes (that’s the usual lifetime of the DID token) to check your email inbox. You will receive an email with the magic link to complete the authentication process.
After authentication, you need to return to the dashboard and check the Users tab to make sure that the registration is completed. If your email address is there, the registration is successful.
Let’s get back to the form handler. If the authentication is successful, loginWithMagicLink
returns the DID token that is used to check the status of the request.
If we receive the token, then we make a redirect to the homepage. If an error occurs, there won’t be any action.
The homepage code looks like this:
return (
<>
<Head>
<title>Home</title>
</Head>
<div className={styles.container}>
<div
className="
max-w-sm bg-white rounded-lg border
border-gray-200 shadow-md dark:bg-gray-800
dark:border-gray-700 m-auto mt-12
"
>
<div className="flex flex-col items-center pb-10 px-4 pt-10">
<Image
height={100}
width={100}
className="w-24 h-24 rounded-full shadow-lg"
src="/avatar.svg"
alt="Bonnie image"
/>
<h5 className="mb-1 mt-3 text-xl font-medium text-gray-900 dark:text-white">
{ email }
</h5>
<div className="flex mt-4 space-x-3 lg:mt-6">
<button
onClick={handleSignout}
className="
inline-flex items-center
py-2 px-4 text-sm font-medium
text-center text-white bg-blue-700
rounded-lg hover:bg-blue-800
focus:ring-4 focus:ring-blue-300
dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800"
>
Logout
</button>
</div>
</div>
</div>
</div>
</>
);
We need to use the getMetadata
method to display the user’s email.
useEffect(() => {
const getData = async () => {
try {
const { email } = await magic.user.getMetadata();
setEmail(email);
} catch (error) {
console.log("Error", error);
}
};
getData()
}, []);
As you can see, there are not too many functions to discuss, so let’s move on to logout. The user obviously won’t like the idea of manually cleaning up indexedDB, so you need to implement the logout
method that will clean everything up automatically.
const handleSignout = async (e) => {
e.preventDefault();
try {
await magic.user.logout();
router.push('/login');
} catch (error) {
console.error("Error", error);
}
}
Last but not least, we need to protect our page from unauthorized users. You can use isLoggedIn
to secure your page. To implement that solution, add this code to pages/_app.js
:
const router = useRouter();
useEffect(() => {
const checkAuth = async () => {
const isUserLogged = await magic.user.isLoggedIn();
if(isUserLogged) {
router.push('/');
return;
}
router.push('/login');
}
checkAuth();
}, []);
Magic SDK provides everything you need for passwordless authentication. There is nothing more to add. Check the results of our work here.
A final note
Instead of closing with a long paragraph, here’s the link where you can test all your passwords to see if they’ve been compromised.
To sum up, we have covered how to implement practical passwordless authentication in an application using magic links. You can follow a similar process to implement passwordless authentication today!