
Show HN: Emauth.io – Free service for Slack-style passwordless login links - anderspitman
https://emauth.io/
======
kichik
I think Slack has an extra step where it sends some token from the browser
that opened the link to the Slack app. This way just opening the link is not
enough. Links can be opened by the controller of the email even if they didn't
make the original request. Links can also be opened by something scanning the
email before the user sees them. Neither of these potentially malicious use-
cases are covered by emauth.io.

~~~
vi-mode
Out of curiosity: Which email service is opening links itself? Yes, they scan
attachments or check for domains known being malicious but opening links??

~~~
gruez
If you don't visit the link, you only have the url to go by. If you visit the
link, you can analyze the contents of the page as well.

~~~
anderspitman
So what happens when an email scanner opens a Slack link?

------
stevekemp
Congratulations on allowing `"$(curl
[https://steve.fi/)"](https://steve.fi/\)") <steve@steve.fi>` as an email
address, and not getting exploited!

(I've seen too many systems in the past where they shell out to the command-
line for delivering email, I had to try it!)

~~~
anderspitman
Ha thanks. That's scary. Fortunately I learned at least that much in my
security class.

------
StavrosK
Why does this need to be a service? I wrote a Django library to do this, all
you need is the ability to send email:

[https://github.com/skorokithakis/django-
tokenauth](https://github.com/skorokithakis/django-tokenauth)

~~~
anderspitman
I don't see it as a winner-takes-all market. If someone is using django they
probably _should_ use your library.

~~~
StavrosK
Sure, but why is it a service as opposed to a library? What is the advantage
of a service for this? It seems to me it's just so the author can get paid,
which is fair, but that's not a selling point that appeals to me, the user.

~~~
anderspitman
> Sure, but why is it a service as opposed to a library?

In what language? Sometimes a service is nothing more than a library where
HTTP is the ABI.

------
jeffbarg
I really love the idea of this - lightweight auth is desperately needed in the
web ecosystem (Auth0 is close, but a bit too complicated and bloated).

Would be great if the service returned something like a JWT or just a signed
copy of the email address verified (potentially with an expiry date). That way
you can use the token itself as authentication without making network calls on
the backend to verify it on each call. Not saying this is necessarily
production-grade security, but could suffice for small projects where ease-of-
use is more important than token revocability.

~~~
anderspitman
Thanks for the feedback. I totally agree about simple auth.

emauth is intended to be very barebones. On it's own it really doesn't do
much. You still need to have some sort of session management on your server.
What emauth saves you from is having to worry about generating/storing
passwords.

Returning a JWT is an interesting idea. Can you explain more what that would
look like? Obviously anything that involves consulting emauth.io for every
request isn't going to work. But maybe there would be a simple way for emauth
to delegate token verification to your server.

~~~
y4mi
Jwt are usually signed with a private key, and the corresponding public key
you need for verification is static/fetchable for dog-and-world.

Not sure why he wants you to implement another oauth server though, there are
several quite good (i.e. keycloak) around at this point.

~~~
anderspitman
Oh that makes sense. Idk, I think that's actually a good deal simpler than
oauth. With a single request you get a token that says emauth.io verifies that
at X time the owner of this token had control over Y email address. Anyone can
then use emauth.io's public key to verify the claim. This makes the "email
whitelist" use case trivial to implement on the server. You just have to have
expiration logic.

~~~
y4mi
I don't see how. There are libraries to interface with these oauth solutions
so you basically just send them to the corresponding server and wait for them
to come back with their token , which you'll verify with said library...
You're done

~~~
anderspitman
Do you have an example of such a library/service?

~~~
y4mi
I should probably point out that I'm talking about an authentication framework
which includes sessions etc. I just can't see any other way for jwts granted
by your service to be useful.

If it sounded like your service already exists as an open source solution with
libraries for every language... I don't believe it does, it at least I don't
know about it.

You could actually implement it with a module in keycloak, but you'd need to
write the code yourself. Though it shouldn't be too hard

[https://www.keycloak.org/](https://www.keycloak.org/)

[https://www.keycloak.org/downloads.html](https://www.keycloak.org/downloads.html)

There are community libraries for other languages as well.

And lots of code example for custom authentication flows like

[https://github.com/stianst/keycloak-
experimental/tree/master...](https://github.com/stianst/keycloak-
experimental/tree/master/magic-link)

And an example implementing the auth flow with libraries for a webservice
[https://github.com/houmie/sso/blob/master/src/app.py](https://github.com/houmie/sso/blob/master/src/app.py)

(I'm unrelated to all links, just got them from quick Google searches)

~~~
anderspitman
A way it would be useful without sessions is if you have a webapp that loads a
list of email addresses on startup. For each request that comes in, it checks
if the request has an emauth JWT (maybe passed in a Emauth-Token header). If
it does, it verifies the sig, then checks the contained email address against
the whitelist. If it matches the request goes through.

~~~
y4mi
Yeah, but how would you log a user out? Delete the local token? And if someone
got access to the token, your account will be owned forever with no way to
revoke the access. Unless you auto expire them... Now you need a flow to
refresh the tokens....

If you implement jwt, you will need sessions and all other features
authentication servers have... It would be way easier to implement a custom
authentication flows mimicking your email auth than recreating everything
else.

I think your service is good as is and introducing jwt to it would be a net-
negative

But I'm just a random person from the internet, do whatever you feel like
doing ;)

~~~
anderspitman
Sorry, I didn't notice you had responded. I think maybe you're reading too
much into adding JWTs to emauth.io. It simply provides another source of
information, ie that as of a certain time, emauth.io verifies that the holder
of this token had control over the email address. Implementations can do
whatever they want with that information, depending on their threat model. And
since previously the API was returning a fairly redundant text response
(status code already tells you whether verification was successful), returning
the JWT doesn't interfere with the previous functionality.

------
vi-mode
Nice that somebody is finally offering this as an service. But the service is
full of deal-breakers (for me at least):

> Any given email address can only be verified a certain number of times each
> month.

How many times?

> If you subscribe to emauth pro for $4/month, you can make 512 verifications
> per month

512 verifications for $4/month is a big ask. Auth0 and Firebase have bigger
free tiers, not 100% sure though.

> If you need more verifications than this (for example if you want to use
> emauth for a public app with many users), please contact sales at sales ...

Before you start enterprise sales, some options which are bigger than 512
would be great and I am also not sure if this type of smaller service would
justify any enterprise sales. However, let us know if anyone contacted you for
some enterprise-y deals.

> Also, in order to protect the email sender reputation for emauth, we
> aggressively blacklist ip addresses that repeatedly make requests to invalid
> email addresses.

Makes sense but how long are these IP blacklisted? How many requests are
required to blacklist an IP? Btw, this won't help OPs email reputation, just
few dozens of bounces are required to get your domain on many blacklists. How
did other people solved this problem? How did Medium worked around this
problem in its early days?

Biggest problem though:

Integrating something like your service is easy but building processes around
creates a light lock-in and getting the stuff out again is some work. Looking
at your landing page which I like because it's light and subtle, it still
gives the feeling that it's hobby project and nobody knows if you are still on
the market next month or next year.

Smaller problem:

No custom domain possible (or is it?), so customer might miss that your email
belongs to my service.

~~~
anderspitman
Thanks for the feedback

>> Any given email address can only be verified a certain number of times each
month.

> How many times?

Currently 10. It's a mostly arbitrary number intended to be enough for adding
simple authentication to things like family photo albums, where infrequent
logins and longlived tokens are more acceptable.

>> If you subscribe to emauth pro for $4/month, you can make 512 verifications
per month

> 512 verifications for $4/month is a big ask. Auth0 and Firebase have bigger
> free tiers, not 100% sure though.

512 is a complete shot in the dark. The unfortunate truth is there's no way to
get a feel for a good number until you measure usage and/or get feedback. And
no one is going to give you feedback until you hit the front page so...

>> If you need more verifications than this (for example if you want to use
emauth for a public app with many users), please contact sales at sales ...

> Before you start enterprise sales, some options which are bigger than 512
> would be great and I am also not sure if this type of smaller service would
> justify any enterprise sales. However, let us know if anyone contacted you
> for some enterprise-y deals.

Don't disagree. But I have no data to make tiering decisions from and wanted
to have at least some paid option right away.

>> Also, in order to protect the email sender reputation for emauth, we
aggressively blacklist ip addresses that repeatedly make requests to invalid
email addresses.

> Btw, this won't help OPs email reputation, just few dozens of bounces are
> required to get your domain on many blacklists.

That's good to know, thanks.

> Integrating something like your service is easy but building processes
> around creates a light lock-in and getting the stuff out again is some work.
> Looking at your landing page which I like because it's light and subtle, it
> still gives the feeling that it's hobby project and nobody knows if you are
> still on the market next month or next year.

I'm no fan of vendor lock-in, believe me. I never would have made this if I
didn't need it for my other products and services. Worst case maybe the free
tier is useful for a few people. The service is trivial enough that you can
implement your own fairly easily. I'm sure it's already been implemented a
million times. And if it comes down to me no longer being able to run the
service for some reason, I'll open source it.

> No custom domain possible (or is it?), so customer might miss that your
> email belongs to my service.

Not currently. You can customize the email text a bit to make it clear where
the email originated from.

------
mhe
Looks interesting and easy to integrate. We recently developed something
similar as a module for the Caddy web server: [https://github.com/TNO/auth-by-
email](https://github.com/TNO/auth-by-email)

We developed it for a website that needed (simple) authenticated access for a
read-only website, but we didn’t want to store the (hashed) passwords.

Additional features:

\- email addresses for the whitelist can be stored as keyed hashes with the
key provided at run-time. This way the whitelist is not on on disk in
plaintext.

\- Adminstration of the whitelist is done by email: upon entry of an unknown
email address, the administrator gets an email with a link with which the new
entry can be approved or denied.

\- Kiosk-mode: user enters e-mail address on laptop, receives link on mobile,
clicks link on link in mobile browser. Server detects that it is a different
browser, gives user the option to login on session on laptop (for one day) or
for session in mobile browser. Useful for giving demos.

------
scottmcf
Looks like email security software will automatically follow the link and mark
it as verified, without me clicking on the link.

~~~
anderspitman
That's a great point. Apparently gmail and fastmail, which are what I use
personally, don't do this, so it's not something I came up against in my
testing. I'm definitely going to need to handle that.

~~~
dsl
Test with Outlook, they tend to be the most aggressive at hitting links. Gmail
is based on some reputation secret sauce or possibly a random number
generator. You'll also want to test sending to domains that use FireEye and
similar security products.

In general: links will get followed, javascript will be executed, buttons will
get clicked, and subsequent links will be spidered too.

~~~
anderspitman
Thanks for the info.

------
tjoff
Email addresses ought to be handled with care. I'm sorry but I hope few would
trust any third party service with their customers/users email addresses just
like that.

~~~
anderspitman
Valid concern. I figured it went without saying, but obviously nothing goes
without saying. I added a privacy disclaimer to the bottom of the page. We
don't use the emails for anything other than authentication and internal
analytics for billing.

------
franky47
This is cool. One improvement could be to add a redirection URL as a parameter
in the request so that users land back on the app.

~~~
anderspitman
Thanks! One tricky thing with that is spammers could use emauth with an email
list to send people (at least anyone who clicks the link) to whatever site
they want.

------
willio58
I'm getting an ERR_CERT_INVALID, doesn't bode well for an authentication
service.

~~~
gruez
Works fine for me. I got a letsencrypt certificate valid starting Saturday,
December 28, 2019 and ending on Friday, March 27, 2020.

