Intro to Authentic

November 12th, 2015

An introduction to using Authentic to add authentication to your web apps and microservices.



I. What's this Authentic thing?

Authentication is knowing who a user is. Authorization is knowing what a user is allowed to do. Authentic helps with authentication by letting you identify a user by their email address in your apps and services. Once you know a user's email address, you can use this as a unique ID to handle authorization.It's also useful as an ID for storing and retrieving other info and meta data (like name, phone number, address, etc...).

Authentic can be run as a standalone server that will sign users up (get their email and password), send them a confirmation email (so you know that it's them), and of course let them log in. In this case, when they log in, Authentic will respond with an authentication tokenThe token is a JSON Web Token or JWT. Essentially it's an encrypted JSON object. that can be used by other services and apps to know the user's email -- without having to make a request to a central server each time.

Authentic can also help on the service and client sides to make requests to the server and decrypt the token. Here's how the whole system would look for a user logging in and requesting a report from a separate microservice:

Authentic Cycle

Of course, the user doesn't have to log in for each request, and the microservice can cache the server's public key, so 99% of the time it would just be this:

Authentic Typical Cycle

II. Sounds cool, why would we use it?

Here's a common situation: your company has a bunch of microservices, and you need to make sure that they are only accessible to the people you deem worthy.

For example, let's pretend you're in charge of engineering for ScaleHaus, and for simplicity, you want to start your microservice empire with the following two apps/services: reporting.scalehaus.io and admin.scalehaus.io. reporting.scalehaus.io is your reporting/analytics microservice and is a JSON REST API and admin.scalehaus.io is a single-page-app UI for viewing reports that lives on a CDN and has no server component.

To add authentication and authorization (restrict access to ScaleHaus employees) you could do the following:

1) Create an authentication server with authentic-server and make it available at auth.scalehaus.io.

2) Use authentic-client to add views to admin.scalehaus.io for signup/confirm/login/reset-password and for requests to reporting.scalehaus.io.

3) In reports.scalehaus.io, use authentic-service to decrypt the authentication token provided in the request and verify the user's identity and that their email ends in "@scalehaus.io".

III. OK, let's do it!

Great, glad you're on board. Let's walk through building out the hypothetical situation above.

Step 1: The Server

First, grab your favorite terminal and create a new directory for your authentication server (auth.scalehaus.io in the above scenario):

Next, we'll create our public and private keys:

Now that we have those, we can create our server. Create a new file server.js Fun fact: npm start will run node server.js by default and use authentic-server like so:

Then run npm start and you should have your auth server running. To test it out, let's open a new terminal and use curl to sign up a new user:

The response to the curl should look like this:

And your auth server should have logged something like this:

There are two things to note. First, because the sendEmail function we gave authentic-server doesn't actually send email, it just logs the email data to the terminal, that's what it did.If you'd like to see an example of a sendEmail function that actually sends email, here's one using Mandrill and powerdrill Second, when you sign up a user, authentic-server requires three things: 1) email 2) password 3) confirmUrl. To confirm a user, we want to verify that the user owns that email address. To do this, we send an email to that address and they return with the correct confirmation token. confirmUrl is where we'd like them to return to.

Astute readers will note, however, that the url we provided doesn't exit yet, and we can't confirm our user -- let's change that real quick.

Step 2: The Client

Create a new, separate project and directory for our "admin" app:

This app will be client-side only, so we'll make life easy by using wzrd to give us a static server that will automatically run browser JS for us:

npm i --save wzrd

Once that's done, edit your package.json to add a start script that will run wzrd index.js. The relevant part of package.json should look like this:

To verify that it's working, let's add an obnoxoius alert to index.js:

echo "alert('hi from wzrd')" > index.js

Now let's npm start and open the app by going to http://localhost:9966 in your browser of choice. You should see the alert.

Rockin, we have our browser code up and running. Let's use authentic-client to provide an interface to our auth server. Install authentic-client:

npm install --save authentic-client

Now we'll create a user interface using authentic-client to talk to authentic-server. We could do this part with React, Mercury, Backbone, Angular, Elm, Mithril, etc... but for simplicity copy this vanilla approach into index.js and reload. You should see something like the following:

Authentic UI

Feel free to go through the sign up/confirm/login flow. 95% of index.js is now UI wrangling, but you can see examples of authentic-client's use in signupRoute, confirmRoute, and loginRoute.

Once you log in, the UI will attempt to hit your not-yet-created microservice. Your nonexistant microservice will not respond, and you'll see a network error.

But here's the good news: all that's left now is to create a microservice with a protected endpoint!

Step 3: The Service

Open up a new terminal and create a new project/directory:

Create an http server in server.js that uses authentic-service like so:

Once that's running you can either use authentic-client (either in node or in browser) or curl to make authenticated requests.If you use curl or are crafting the HTTP request yourself, place the auth token in the Authorization header using Bearer schema. It should look like this: Authorization: Bearer eyJ0eX.... For more info see How do JSON Web Tokens Work?

Feel free to change the authorized email(s) in authorized to either block or allow requests based on the identity of the user.

That's it!

You now have the basic scaffold for handling authentication with microservices: a standalone authentication server, a client/UI for handling user logins, and a protected microservice.

Nice work!

If you have any questions or ideas, feel free to reach out on Twitter or Github.