Static Website Authentication with Magic Link Made Easy
Following up on A Login Security Architecture Without Passwords I recently had the opportunity to try out how easy it is to actually implement the "no password" login architecture. The problem to solve was publishing a small static website (an online conference program) to be accessible by several hundred people, of whom we only have the email address (that they used to sign up for the event). The event is private and the program should therefore also not be published to the open Internet, but stay private. In this example the conference program was a custom built website published via static website hosting.
The code and more information on how to get started is published at
github.com/schlomo/static-website-with-magic-link-auth
Problem Analysis
Magic link authentication (get a link via email to log in instead of bothering with a password) is in my humble and honest opinion the best — if not only — solution for this problem (see also my talk 🎦 Lifting the Curse of Static Credentials:
- it relies on the available information — the email used to sign up for the event
- it doesn't make any assumptions on the users' environment or preferences — works on any device
- it doesn't collect more information than strictly required (no phone, first / last name or other personal information)
In a nutshell, the process looks like this (click for more details):
To make our implementation even simpler, there are additional factors we can take into account. Specifically the conference program should not be public on the Internet, but it is OK for users to share it privately:
- the security requirements of the conference program are moderate, so that a simple one-time verification of the participants is sufficient. Combined with a long lasting session, this means that users need to "sign in" only once per device.
- we can accept the risk of users forwarding the magic link (this is important as users could use a different email between signing up to the conference on their PC and accessing the conference program on their phone) or accessing it from a different devices (e.g. sign in on PC and phone with the same link).
- we can accept the risk of session hijacking and other attacks happening on the users' side (this is not a banking app 🤪)
Solution: Static Website with Magic Link Auth Docker Image
Initially I wanted to find a ready made solution for this, but sadly couldn't find any. So a bit of LLM-supported coding later I'm happy to present simple static website hosting solution with built-in magic link authentication:
- Based on NodeJS Express to serve static content and handle the magic link authentication
- Using standard libraries like nodemailer to send out email
- Data privacy friendly, using only email for login and not even storing that in the configuration or the session info
- Operations friendly, no database or persistent storage used (accepting the security / risk trade-offs mentioned above)
- Deployment friendly, simply replace your existing static website Docker image with this one to add authentication
Other solutions to consider would be facilitating a CDN with dynamic authentication handling, like Cloudflare Workers. However, for this case I chose to develop a solution that doesn't depend on a specific hosting environment or Cloud service.
Live Demo
Implementation Details
To keep the implementation very simple (the entire solution fits into less than 1000 lines of code including comments) and data privacy friendly, we use some tricks:
The ongoing authentication verification is based on a cryptographically signed
session. The session is stored in a cookie that is not accessible via
JavaScript. The session only contains
{"authenticated": true}
as information, we don't care about the
user identity for this simple use case. The actual security is based in the
signature of the session, that prevents manipulations by a user. The signature
is created with the help of a static secret known only to the server. For the
given use case I think that this is "good enough".
The login is handled via a token that is encrypted and emailed to the user
upon request. The token only contains
{"expires":1746433589349, "redirect": "/about.html"}
which is the validity of the login link (typically 15 minutes) and the path to
go to after signing in. Again we don't care about the user identity after
checking it in our list of allowed emails. The login link takes the a function
that verifies the token, sets the session to be authenticated and redirects
the browser to the actual static website content. At this stage we already
don't know the identity of the user as we don't keep that information
anywhere.
The list of allowed emails is currently provided via a simple text file as part of the application. This text file accepts both plain email addresses and also SHA-256 hashes. All emails are hashed on import and stored only as hashes.
Configuration & Deployment
Configuration happens via environment variables, see
server.js
for a full list of supported variables and their defaults and the project
README.md
for more information.
You can deploy it to any Javascript hosting service, use my Docker image directly, or base your own Docker image on it.
For a quick test run the
Git repository
contains an
example.env
configuration that works for sending emails to Google accounts without
requiring an email sending service.
Lessons Learned
Moving away from passwords is much easier than I feared myself — and it can significantly increase the security posture and reduce the data privacy risks. Even if my server would get hacked there is literally nothing on it that is secret, especially if the email addresses are already hashed in the configuration.
Most of the time implementing this was spent on polishing the code and solving edge cases, while the actual magic link solution was very easy to build. I hope that this little example will help you to protect your own static website with a simple login mechanism. And maybe it can motivate you to get rid of passwords in other places, too.
Interested in how you can get rid of passwords in your environment? Please reach out to us, Tektit Consulting and I are happy to support you in getting rid of passwords, increasing the user experience and improving your securite posture.
Comments
Post a Comment