An Email-Only Authentication Scheme

When a user arrives at your website hoping to use one of your services, you need to ensure 1) that they are who they say they are (authentication) and 2) that they are allowed to use the service they are trying to use (authorization).

An email-based JWT (JSON Web Token) authentication scheme can cover the first need and the resulting token can be used for the second.

What is a JSON Web Token?

If you're unfamiliar with JWTs I'd recommend checking out the excellent introduction at JWT.io. In short, JWTs provide a way to securely share information between two parties. In this case, "secure" means "hasn't been tampered with", as opposed to encrypted (we'll rely on SSL for encryption).

This authentication scheme can be broken down into a few steps for a new user:

  1. Get the user's email
  2. Generate a single-use JWT and send it to the user in a link over email
  3. When the user clicks on the link, invalidate the single-use JWT and generate a new, longer lived JWT and send it to the user
  4. Send the user's token in every request via the Authorization header

This scheme only works if all requests are served over HTTPS, which encrypts traffic in transit. If any requests are made over HTTP the token will be visible to anyone inspecting web traffic and they can act as that user.

Get User's Email Address

When someone tries to use our service, but doesn't yet have a token or has an invalid token, we'll need to authenticate them.

User Doesn't Have A Token

We'll be storing the token as a cookie, so when the user tries to make a request, our javascript should check for the presence of that token. If the user doesn't yet have a token, we need to ask them for their email address, which we can do in a single field form, like so:

Invalid Token

The additional case we'll need to cover is if our user has an invalid (likely expired) token. Our backend will need to handle the token validation (more on that later). In this case, our client-side javascript sees the token containing our cookie and makes the request to our backend, which either responds with the requested data if the token is valid or a 401 if it isn't.

If we've got an invalid token, no worries, we'll just need to ask the user to authenticate again.

Generate Single-Use JWT

Once we've POSTed the user's email address to our backend we'll want to create a JWT with a unique secret and a short expiration. We'll then send the token to the user as a link in an email that points to an endpoint for handling these single-use JWTs.

Why should this JWT be short-lived?

Because email isn't reliably secure so the short expiration allows us to avoid leaving the token lying around for some bad-actor to pick up and use.

User Clicks On Link

When the user clicks on the link in their email, our backend will need to invalidate that token and generate a new token with a longer expiration using a new secret. After invalidating this first token, we respond to this request by redirecting the user to the desired destination, using the Set-cookie header to save their new token as a cookie for our domain.

Using Token In Authorization Header

Subsequent requests should include the token in the Authorization header. Endpoints that require authorization should then inspect the token and validate it using the secret associated with this user to ensure that the token hasn't been tampered with.

That's It!

The user is now free to use our site password-free and we can have some confidence that the token holder is in-fact the owner of that email address. We can now use their email to determine what services that user has access to.


If you appreciate the simplicity of this auth system, you might enjoy the simplicity of bugbucket.io.

BugBucket provides public issues for private repositories, so your users can submit bug reports and feature requests to the same place that you'll resolve them.