Passwordless Authentication with Phoenix Tokens

On Apr 24, 2017 by Pete Corey

Subtitled: I got 99 problems, but a password ain’t one.

I’m in the process of building a security-focused SaaS application (shameless plug: Inject Detect), and I’ve decided to use a passwordless authentication scheme. Since I’ve decided to stop using passwords, I feel like a great burden has been lifted from my shoulders.

In this post, let’s dig into how awesome passwordless authentication is, and just how easy it is to set up in your Elixir/Phoenix application.

Passwordless in a Passwordful World

Before we dig into the nuts and bolts of building out a passwordless system, we should probably talk about what exactly “passwordless” means.

How can we authentication users without passwords?

The general idea behind a passwordless authentication scheme is that instead of a user regurgitating a password to prove their identity, they’re emailed a “magic link” that, when clicked, will activate their session.


In many ways, a passwordless authentication scheme is very similar to traditional password-based authentication. The only difference is that we require the user makes a trip to their inbox.

So why bother? Shouldn’t we focus on creating less work for our users? Aren’t passwords fine?

It turns out that passwords aren’t fine. There are numerous problems with passwords as we know them. Not only do people often choose poor passwords and have deplorable password habits (full disclosure: I’m one of these people), but they fundamentally don’t do the job they’re designed to do.

How so?

Authentication ultimately boils down to proving you are who you say you are. This is often done by presenting the system with a fact that can only be known by you. If you can produce this fact, the system assumes that you are who you say you are.

Unfortunately, your passwords aren’t secrets only known by you. Every time you use (or reuse) a password in a system, you’re giving that system knowledge of your password. You’re trusting the ethics and technical competency of that system with the defining factor of your online identity.


How is passwordless better?

I believe that passwordless authentication is a better alternative over password-based authentication for the simple reason that turns authentication into a process of active consent, rather than the passive transfer of a piece of information.

Your active consent cannot be given to another system, or stolen by an attacker. As long as you control the channel through which consent is granted (email, SMS, etc…), you control your identity.

Take the power back!

Going Passwordless with Phoenix Tokens

Now that I’ve spent all that time waxing poetic about the beauties of passwordless authentication, let’s talk about how can actually implement it in a Elixir/Phoenix based application.

I debated going into great detail in this section discussing how to implement passwordless authentication in a few different stack permutations (Vanilla Phoenix, React, Apollo, Absinthe, etc…), but instead, let’s talk about the common theme in all of these implementations: Phoenix Tokens.

Phoenix Tokens do two things that turn out to be invaluable for building out a passwordless authentication scheme:

  • They generate cryptographically strong bearer tokens.
  • They let you make assertions about the age of a token.

There are three major workflows of a passwordless system. Let’s run through each of them and see how easy they are to implement using Phoenix Tokens.

Signing Up

In a passwordless system, all we need to create an account for a new user is their email address.

If we don’t care to verify the email address they provided, we can immediately sign them in by using Phoenix.Token.sign to generate the user an auth_token:


Phoenix.Token.sign(Endpoint, user.id, :crypto.strong_rand_bytes(32))

This auth_token will be saved and passed down to the client and stored in localStorage. Any subsequent requests to the server will send along this token to identify the currently logged in user.

When the server receives a request with an attached auth_token, it can look up the associated user.

If we want to limit the maximum age of a user’s session, we can verify the token using Phoenix.Token.verify and pass in a :max_age in seconds:


Phoenix.Token.verify(Endpoint, user.id, auth_token, max_age: 1209600)

In this example, we’re limiting sessions to two weeks (or 1,209,600 seconds). If a user tries to use an expired token, or a token not associated with any users, we return an error.

Signing Out

Once our new user has signed up, signing out is as simple as deleting their associated auth_token.

Once the auth_token is removed, and cleared from their browser’s localStorage, all subsequent requests they make will be unauthenticated until they sign back in.

Signing In

Now we’re getting to the interesting part.

Once our user has signed out, how do they sign back into our passwordless application?

On the “sign in” page, the user will enter their email address and click a “Send me a magic link” button. Next, our server will use Phoenix.Token.sign to generate a new requested_token, which will be saved and emailed to the provided email address.


Phoenix.Token.sign(Endpoint, user.id, :crypto.strong_rand_bytes(32))

The email will contain a link to a “verify requested token” route in our application which takes the requested_token as a parameter.

That route looks up the user with the provided requested_token, verifies that the requested_token isn’t expired, generates a new auth_token for that user, and finally removes the verified requested_token from the user:


Phoenix.Token.verify(Endpoint, user.id, requested_token, max_age: 600)

Phoenix.Token.sign(Endpoint, user.id, :crypto.strong_rand_bytes(32))

In this example, our “magic link” emails only last for ten minutes.

Once a user clicks the link, their new auth_token will be sent down to the client and they’ll be automatically signed in!

Final Thoughts

Passwordless authentication is definitely new territory for me, and I suspect, a lot of other software developers.

I strongly believe that it’s important to explore other options for user authentication. The status quo simply isn’t working. Whether you look at it from a user experience perspective, or from a perspective of security, traditional passwords in practice are ineffective and wrought with problems.

Passwordless authentication may not be the ideal solution, but I believe that it’s a step in the right direction.

If you want to see passwordless authentication in action, sign up for the Inject Detect newsletter to receive the latest news on its upcoming release!

Who Needs Lodash When You Have Elixir?

On Apr 17, 2017 by Pete Corey

Before adventuring into the land of Elixir, I used Javascript day in and day out for both front-end and back-end development. Javascript’s (lack of) standard libraries forced me to rely heavily on third-party tools and libraries such as Underscore and Lodash.

I became very proficient at working with these tools, and after initially starting with Elixir, I felt very clumsy with the new language. I wasn’t able to accomplish the things I could easily and quickly do with Javascript and Lodash.

Over the past few months, I’ve become much more comfortable with the language, and I’ve realized that Elixir’s standard library outclasses Lodash in nearly every way.

Let’s dig into the two and see how we would translate the Lodash-isms we know and love into Elixir code.

The Usual Suspects

For many functions in Lodash, there’s an obvious mapping to an equivalent function in Elixir’s standard library.

For example, the usual suspects like _.map, _.reduce, _.find, and _.filter all have equivalent functions in Elixir’s Enum module:


_.map([1, 2, 3], n => n + 1)  // Enum.map([1, 2, 3], &(&1 + 1))

_.reduce([1, 2, 3], (s, n) => s + n)  // Enum.reduce([1, 2, 3], &(&2 + &1))

_.includes([1, 2, 3], 2)  // Enum.member?([1, 2, 3], 2)

_.filter([1, 2, 3], n => n < 3)  // Enum.filter([1, 2, 3], &(&1 < 3))

Other commonly used Lodash functions such as _.uniq (Enum.uniq), _.find (Enum.find), _.keyBy (Enum.group_by), etc. also have their counterparts in the Elixir standard library.

Getting Nested Values

I’ve also come to heavily rely on Lodash’s _.get and _.set functions to grab and update values in deeply nested data structures.

Using _.get lets me grab a nested value (or undefined) even if the intermediary objects and arrays don’t exist. For example, instead of writing:


if (foo && foo.bar && foo.bar.baz) {
  return foo.bar.baz.bot;
}

I can simply write:


return _.get(foo, "bar.baz.bot");

When I first started working with Elixir, I really missed being able to do this. Working with complex, nested data structures felt so clunky! That was before I found out about the awesome power of Elixir’s Access behavior and the family of functions built around it.

In Elixir, we can use the get_in function to grab values (or nil) out of nested structures, even if the intermediary values don’t exist:


get_in(foo, [:bar, :baz, :bot])

We can even pass in dynamic lookup fields, which would have required string manipulation in the Javascript example:


get_in(foo, [:bar, some_id, :baz])

Additionally, we can use Accessor functions to take our Elixir-foo to the next level. For example, we could grab the second user’s name (if it exists, otherwise we get nil):


get_in(..., [:users, Access.at(1), :name])

Or we could grab all of the users’ names:


get_in(..., [:users, Access.all(), :name])

If we wanted any of these values or intermediary values to have a default value, we could use Access.key:


get_in(..., [:users, Access.all(), Access.key(:name, "Anonymous")])

Let’s see Lodash’s _.get do that!

Setting Nested Values

All of these ideas apply to updating values as well. We can use put_in to directly set a value in a nested data structure, or update_in to update it with a function we provide.

For example, we can set values deep in a data structure, even if the intermediary values don’t exist, with put_in and Access.key:


put_in(%{}, [Access.key(:foo, %{}), :bar], "baz")

Similarly, we can update values with update_in or get_and_update_in.

If the Accessors provided by Elixir’s Access module aren’t enough for your use case, you can even write your own custom accessor functions!

Out of the Box Chaining

Elixir’s proverbial cherry on top is undoubtedly its built-in pipe operator.

To pipe Lodash function calls together, you need to explicitly construct a function chain with _.chain, passing in your initial value, and then call _.value at the end of your chain to retrieve the resulting value.

For example, let’s say we want to count the number of orders a set of users has made:


_.chain(users)
 .map("orders")
 .map(orders => orders.length)
 .sum()
 .value();

Because of Elixir’s stateless, functional nature, the barrier of entry for starting a chain is nonexistent:


users
|> Enum.map(&(&1.orders))
|> Enum.map(&length/1)
|> Enum.sum

Final Thoughts

I’ve yet to find a problem easily solvable with Lodash that isn’t easily solvable with an out-of-the-box tool provided by Elixir. In my experience, Elixir has proven to be incredibly more flexible and more powerful than Lodash.

While I originally felt uncomfortable and clumsy working with data in Elixir, my ever growing understanding of the tools the language provides is helping me regain my confidence.

If you haven’t already checked out Elixir, do it!

If you’re new to Elixir and feeling like a fish out of water, my only advice is to stick with it and read through the guides and documentation. You’ll be swimming again in no time.

Using Apollo Client with Elixir's Absinthe

On Apr 10, 2017 by Pete Corey

Last week I wrote about how I’m using Create React App in conjunction with the Phoenix framework to get off the ground incredibly quickly when building single page applications.

In that post I gave a teaser of how you can integrate your React front-end with your Elixir/Phoenix back-end using GraphQL and the Apollo client.

Let’s dive deeper into how we can wire up an Apollo driven React application to our Absinthe/Phoenix back-end.

Getting Started

Before we get started, let’s make sure we’re on the same page.

The Apollo client is a powerful GraphQL client with a variety of framework-specific integrations. Absinthe is an Elixir-powered GraphQL server implementation with built-in support for the Phoenix framework.

Apollo + Absinthe = 😍

In the past I’ve talked about the basics of getting started with Apollo client and Absinthe. Be sure to check out those instructions, and read through the Apollo documentation and the Absinthe guides if you’re unfamiliar with either tool.

For this article, I’ll assume you’re using a project setup similar to the one I described last week. That is, you’re running a React front-end application served through the Create React App tooling that connects to a Phoenix back-end application.

Once that’s all set up, we can spin up our React front-end by navigating to our React application’s folder and running:


npm start

Similarly, we can spin up our Phoenix back-end server by navigating to our Elixir project and running:


mix phoenix.server

Out of the box, our React application will run on port 3000, and our Phoenix server will run on port 4000.

Wiring Our Front-end to Our Back-end

As we mentioned last week, we need a way to tell our React application how to communicate with our back-end Phoenix applications. We do this by giving our application the URI to our GraphQL endpoint.

In different environments, this endpoint might change. That is, our staging environment might point to a different GraphQL endpoint than our production environment.

This means we can’t hardcode these endpoints into our front-end code.

So what do we do?

Thankfully, Create React App lets us pass custom environment variables into our front-end applications as long as they’re prefixed with REACT_APP_. These environment variables are passed into the application by the build tool and can be accessed through the process.env object.

Let’s assume that our GraphQL endpoint will be passed in through the REACT_APP_GRAPHQL_URI environment variable. We can use this to build Apollo’s network interface:


const networkInterface = createNetworkInterface({
    uri: _.get(process.env, "REACT_APP_GRAPHQL_URI"),
});

Now when we spin up our React application, we need to be sure to set REACT_APP_GRAPHQL_URI, otherwise our call to createNetworkInterface will fail:


REACT_APP_GRAPHQL_URI="http://localhost:4000/graphql" npm start

Now our React application knows where to find our Absinthe-powered GraphQL server.

Perfect!

Using a Custom Watcher… Partially

While our setup is now fully functional, having to manage two different development servers is cumbersome. Instead, let’s write a custom Phoenix watcher than spins up our Create React App development server whenever we start our Phoenix server.

We can do this by adding a new watcher to our Endpoint configuration in config/dev.exs:


config :hello_create_react_app, HelloCreateReactApp.Endpoint,
  ...
  watchers: [npm: ["start", cd: Path.expand("priv/hello_create_react_app/")]]

Now whenever we fire up our Phoenix server with mix phoenix.server or even iex -S mix phoenix.server, our Create React App development server (npm start) will spin up as well.

Remember, we still need to set REACT_APP_GRAPHQL_URI!


REACT_APP_GRAPHQL_URI="http://localhost:4000/graphql" mix phoenix.server

Fantastic!


Unfortunately, there’s currently a problem with this solution.

For some reason, when Create React App’s npm start command is executed through a watcher, which ultimately boils down to a call to System.call "npm", ["start"], ..., killing the Phoenix server will not kill the Create React App development server running in the background.

Killing your Phoenix server and trying to spin it up again will give you this error from the npm start command:


Something is already running on port 3000.

You’ll need to manually find the orphaned node process and kill it before once again restarting the Phoenix server.

I believe this problem is related to this issue on Github. Hopefully it will be fixed soon.

Integrating with our Release Manager

We know that we can point our React front-end to different back-ends with our REACT_APP_GRAPHQL_URI environment variable, but how do we automate this?

Is there a way to incorporate this into our release process?

If you’re using edeliver to generate your releases, you’re in luck. You edeliver configuration file can be customized to set REACT_APP_GRAPHQL_URI according to your build target.

Your edeliver configuration (.edeliver/config) is really just a bash script that’s executed before each edeliver task. This means that we can conditionally set REACT_APP_GRAPHQL_URI based on the environment we’re building for:


if [[ "$DEPLOY_ENVIRONMENT" = "production" ]]
then
  REACT_APP_GRAPHQL_API="http://production/graphql"
fi

if [[ "$DEPLOY_ENVIRONMENT" = "staging" ]]
then
  REACT_APP_GRAPHQL_API="http://staging/graphql"
fi

We can then add a compile hook to build our React application’s static bundle:


pre_erlang_clean_compile() {
  status "Installing NPM dependencies"
  __sync_remote "
    [ -f ~/.profile ] && source ~/.profile
    set -e

    cd '$BUILD_AT/priv/hello_create_react_app'
    npm install $SILENCE
  "

  status "Building React application"
  __sync_remote "
    [ -f ~/.profile ]
    set -e

    cd '$BUILD_AT/priv/hello_create_react_app'
    npm run build $SILENCE
  "
}

Now our React application should be built into priv/hello_create_react_app/build/, which is where our Phoenix application expects to find it.

Additionally, when it’s served by our Phoenix application it will connect to either our staging or production GraphQL endpoint depending on the environment the particular release was built for.

Now that our release manager is handling our front-end build process, all we need to worry about it building our application.

Final Thoughts

Once again, I’m very happy with this setup!

So far the combination of using React with Apollo and communicating with my Phoenix server using Absinthe has been a very powerful and productive combination.

As I mentioned last time, building your front-end application independently from your back-end application can offer up interesting optimizations if you choose to go that route.

Alternatively, you can configure your Create React App to be served as a static asset from your Phoenix application. Hopefully this article has shown that that’s a fairly painless process.