Get Started

This guide shows you everything you need to get JustAuthenticateMe working for your app.

Introduction

First, it's important to understand what exactly JustAuthenticateMe provides to your web app.

JustAuthenticateMe uses "magic links" to gain confidence that a user has access to an email address. It then signs a token saying as much and returns it to your app. If you opt in, JustAuthenticateMe can also provide the ability for your app to "refresh" a user's token beyond the initial time period of validity. To learn more of the details of how JustAuthenticateMe works, check out the Security Model.

From your perspective, this will take the form of just 4 steps. That's it. They are:

  1. Tell JustAuthenticateMe to authenticate a user by their email address.
  2. Accept the token(s) that JustAuthenticateMe sends back to your app.
  3. Verify ID tokens on your backend.
  4. (Optional) Refresh the user's session with a refresh token.

With those in place, you'll have strong email based authentication built in to your app.

Creating your App

Before we can get start coding, we need to create an app in the JustAuthenticateMe console. Here's a link..

Once there, you'll see something like this.

Screenshot of JustAuthenticateMe Dashboard

Click "Add App" and you'll see a form pop up like this:

Screenshot of "Add App" form

In the screenshot above, you can see that we're creating an app called "My Cool App - Local Test" that has a redirect URL of http://localhost:3000/jam-redirect and has refresh tokens enabled. This assumes that we have our app running locally on port 3000 to test out JustAuthenticateMe. All of these options are explained in more detail in App Options.

After clicking "Save", you're app will get an ID which you can see on the dashboard underneath the app name. You'll need this ID in your code. We'll refer to this value from now on as the appId.

Screenshot of JustAuthenticateMe Dashboard with a new app and app ID

Initiating Authentication

Now that the boring part is over, we're ready to start authenticating some users!

To get started, install the Web SDK, justauthenticateme-web, for your frontend.

npm install --save justauthenticateme-web
yarn add justauthenticateme-web

The default export of this dependency is a constructor for a JustAuthenticateMe object. Call the constructor with your appId.

import JustAuthenticateMe from "justauthenticateme-web";
const jam = new JustAuthenticateMe("9212112e-0c4f-4271-b6df-4b9e8c344994");

Great, now authenticate someone.

await jam.initAuth("someone@example.com");

That's it!

jam.initAuth returns a promise. On success, you can be sure that JustAuthenticateMe successfully sent an email to the email you passed in. On failure, we ran into an error. This happens most often when the email is invalid.

This is what the email that the user receives looks like.

Screenshot of Log In Email

You can write your own login email for your app using the JustAuthenticateMe console.

Accepting the Token(s)

When a user clicks on the link sent to their email, we provision a token and redirect them to the URL you specified in the JustAuthenticateMe console with a couple query string parameters:

  1. idToken will be a JWT with a couple claims. Most importantly, the email claim will be the user's email.
  2. refreshToken will be a secure token that only this user can use to fetch a new ID token after the current one expires. This is only included if you enabled refresh in the JustAuthenticateMe console.

This ends up being a GET to something like:

http://localhost:3000/jam-redirect?idToken=longBase64String&refreshToken=anotherLongBase64String

How you handle this is up to you. Your server can accept this GET and set a httpOnly cookie with the token(s). Or you could handle this client side by retrieving the values from the URL in javascript. The Web SDK jam object from before has a helper method for this case:

const { idToken, refreshToken } = jam.getTokensFromURL();

There are a plethora of variations on storing and handling user tokens. We provide some guidance, but JustAuthenticateMe is unopinionated on this matter.

Regardless of the details, the idToken will need to be included in authenticated requests to your backend.

Verifying a Token

You'll need to verify an ID Token's signature before trusting its contents. This is typically needed on the backend of your app, before acting on a request for a user. JustAuthenticateMe provides a simple API for accomplishing this.

AWS API Gateway Authorizer and Serverless Framework

If your backend is a set of AWS Lambdas behind API Gateway, you'll have the easiest time integrating JustAuthenticateMe. If you're using the Serverless framework, then you can use the JustAuthenticateMe plugin, and if not you can still take advantage of the pre-made Lambda authorizer.

Serverless JustAuthenticateMe Plugin

See the README for the most detail. In essence, after you npm install --save serverless-justauthenticateme-plugin, you'll add three things to your serverless.yml as described below.

# 1. Add the plugin
plugins:
  - serverless-justauthenticateme-plugin
# 2. Configure the plugin with your App ID
custom:
  justauthenticateme: 9212112e-0c4f-4271-b6df-4b9e8c344994"
# 3. Specify endpoints as requiring authentication
getBooks:
  handler: dist/endpoints/getBooks.handler
  events:
    - http:
        path: books
        method: get
        authorizer: justauthenticateme # just use this value
        request:
          parameters:
            headers:
              Authorization: true

In your frontend, you'll send the ID Token to your serverless backend in the Authorization header as a bearer token.

In your lambdas, you'll access the email of the authenticated user as event.requestContext.authorizer.email.

Lambda Authorizer

See the README for the most detail. In essence, after you npm install --save justauthenticateme-apigateway-auth, you'll create a very simple javascript file that will look like this.

import authHandler from "justauthenticateme-apigateway-auth";
export const handler = authHandler("9212112e-0c4f-4271-b6df-4b9e8c344994");

You'll want to configure this handler as your API Gateway's Custom Lambda Authorizer for any endpoint that you want to be authenticated. Be sure to configure it as a REQUEST authorizer.

In your frontend, you'll send the ID Token to your serverless backend in the Authorization header as a bearer token.

In your lambdas, you'll access the email of the authenticated user as event.requestContext.authorizer.email.

Nodejs

If your backend runs on Node.js, you can use JustAuthenticateMe's Node SDK. You can install it and set it up similarly to the Web SDK.

npm install --save justauthenticateme-node
yarn add justauthenticateme-node

Just like the Web SDK, the default export is a constructor for a JustAuthenticateMe object. Call the constructor with your appId.

import JustAuthenticateMe from "justauthenticateme-node";
const jam = new JustAuthenticateMe("9212112e-0c4f-4271-b6df-4b9e8c344994");

Verifying a token is as easy as:

const email = await jam.verify(token);

verify will throw an error if the token is invalid, in which case you'll typically return a 401. On success, verify returns the email of the user authenticated with JustAuthenticateMe. You can use this value confidently, knowing that the owner of the token owns or has access to that email address.

Under the hood, verify fetches the public key for your app and caches it for all future uses. This means the first call will require a network request, but all future calls only involve the actual cryptographic verification of the token.

Other Languages

For languages that don't yet have a JustAuthenticateMe library, you can still get up and running quickly with JustAuthenticateMe's simple REST API. You can read about all public endpoints on the REST API page. Here, we'll just talk about how to get token verification working.

The quick innefficient way

Just let the JustAuthenticateMe REST API do everything for you. If you POST https://api.justauthenticate.me/YOUR_APP_ID/verify with a json body like this:

{
  "idToken": "usersLongBase64IdToken"
}

The JustAuthenticateMe API will return 200 for a valid token or 401 for an invalid token. You can then extract the email claim from the JWT using any library you'd like for your language.

The reason this is innefficient is because it requires a network call for every verification, which is usually unideal. If this works for your use case, though, feel free to use it!

The involved performant way

If your app needs to be able to verify tokens without a network request each time, then you'll have to do just a bit more work.

First you'll want to fetch your apps public key with a GET https://api.justauthenticate.me/YOUR_APP_ID/.well_known/jwks.json. This will return a JSON Web Key (JWK) set with one entry: your public key. You'll want to cache this key for future use.

JustAuthenticateMe public keys are elliptic curve keys, using the P-521 curve. More details about how the JWT tokens are constructed can be found in the Security Model. Your language likely has a library for parsing JWKs and verifying JWTs with them.

All in all, the pseudo code should look something like this:

app_id = "9212112e-0c4f-4271-b6df-4b9e8c344994"
jwk = None
def verify(token):
    if jwk is None:
        response = https.GET("https://api.justauthenticate.me/" + appId + "/.well_known/jwks.json")
        jwks = parseJSON(response.body)
        jwk = jwks["keys"][0]

    success = jwt.verify('ES512', token, jwk) # assuming a library called "jwt" supports this
    # Most libraries should also check expiration time, which is critical to ensuring expired JWTs can't be used. If your library doesn't support this, you can easily check it yourself by decoding the payload.

    if success:
        return jwt.parse(token).payload["email"]
    else:
        raise UnauthorizedError

Refreshing a Token

If you don't need refreshing, make sure it is disabled for your app in the JustAuthenticateMe console, and you can stop here! Read more about whether or not you need refreshing in App Options.

Okay, you've kept reading so you must want to refresh a user's ID token! Both the Web and Node SDKs support the following method:

const newIdToken = await jam.refresh(refreshToken);

And you're done!

If you need to call this from another language, simply POST https://api.justauthenticate.me/YOUR_APP_ID/refresh with a json body like this:

{
  "refreshToken": "usersLongBase64RefreshToken"
}

and you'll get a response of the form:

{
  "idToken": "brandNewValidIdToken"
}

Wrapping Up

This guide walked through:

  • Creating an app in the JustAuthenticateMe Console
  • Authenticating a user's email address
  • Receiving a user's token(s) after successful authentication
  • Verifying a user's ID token
  • Requesting a new ID token using a refresh token

If you need to know more about features or the internal workings of JustAuthenticateMe, please check out the rest of the documentation!

If this guide is missing anything important or if you have any feedback whatsoever, please reach out to support@justauthenticate.me.