Michael Cordell's Blog

Setting up authentication on a Grape API with GrapeTokenAuth

15 Sep 2015

Grape is a fantastic framework for building an API. Of course, one of the most fundamental aspects of any API is authentication. The grape_token_auth gem is approaching its first major release (0.1.0) and this will provide a “getting started” guide.

In this post, we will walk through setting up grape_token_auth to provide authentication for a simple Grape API. Briefly, grape_token_auth provides helpers and employs patterns that will be familiar to those who have used devise, and is compliant with ng-token-auth and j-toker.

First, we will setup the Grape API, then to enable authentication, there will be three main steps:

  1. Configuring GrapeTokenAuth
  2. Mounting GrapeTokenAuths in the main API
  3. Authenticating endpoints

Before we begin, this guide will be targeting a standalone Grape API. However, there is nothing preventing this guide from being used with a grape app that is side mounted with a Rails App or Sinatra app. We will leave out the database and ActiveRecord model setup portion, but if you are curious, you can refer to the full demo repo here.

Setting up the Grape API

First, install the needed gems with bundler:

# Gemfile

gem 'grape'
gem 'rack'

# using github for now until 0.1.0 is released
gem 'grape_token_auth', github: 'mcordell/grape_token_auth'

Next, let’s create the Grape API on which we will setup authentication. We will define a single endpoint /protected_endpoint. This is where we will eventually enforce authentication.

# lib/grape_token_auth_demo.rb

class GrapeTokenAuthDemo < Grape::API
  format :json

  desc 'This will be a protected enpoint accessible to only authenticated users'
  get '/protected_endpoint' do
    status 200
    response = { message: "Welcome this should be protected" }
    present(data: response)
  end
end

Then, let’s run this as a plain rack app:

# config.ru

require 'grape'
require_relative 'lib/grape_token_auth_demo.rb'
require 'warden'

GrapeTokenAuth.setup_warden!(self)

run GrapeTokenAuthDemo

The setup_warden! line configures the warden gem. At the moment, warden is used to coordinate with other authentication through devise/warden.

Running bundle exec rackup should give you a working, albeit simple, Grape app.

Configure your Active Record Models and setup your database

In this example we will be using an ActiveRecord model User with a table structure that looks like this. Again, if you want to see the full model/database setup, refer to the full repo.

Configure GrapeTokenAuth

Below is a bare-bones configuration:

GrapeTokenAuth.setup! do |config|
  config.mappings = { user: User }
  config.secret = ENV['GTA_SECRET']
end

The GTA secret is similar to devise’s secret, it’s a random hex string used in generating confirmation and reset tokens. Notice, that it is stored in an environment value, and not directly in the repo. If you have a rails app lying around, you can run rake secret from it, you can alternatively use:

require 'securerandom'
puts SecureRandom.hex(64)

Through, the mappings, we are able to link a given scope, in this case :user, to a given model/class User. Scopes help define helper methods e.g. current_user, authenticate_user! and also allow us to define the class that will be used at a given group of GrapeTokenAuth endpoints. It is essential that mappings are set up before using GTA token authentication.

The bare-bones configuration will allow us to use the majority of the authentication endpoints, but if we intend to use email-sending tools we need to setup email-related options. The new options below define the necessary settings for sending emails:

GrapeTokenAuth.setup! do |config|
  #...
  config.mailer = MailgunMailer if ENV['MAILGUN_API_KEY']
  config.from_address = 'gta_demo@grape-token-auth-demo.herokuapp.com'
  config.default_url_options = { host: 'grape-token-auth-demo.herokuapp.com' }
end

from_address defines the address the emails will be sent from, the default_url_options are used to define the host where the Grape API will be hosted. mailer points to the class that will be used to send the messages. grape_token_auth ships with a SMTP mailer through the mail gem, but you can also define your own as shown here.

GrapeTokenAuth is now setup and ready!

Mounting GrapeTokenAuths in the main API

In order to be able to easily mount the authentication APIs, we will first need to include the mount helpers. You only need to include this helper in the specific Grape app where you want to mount the authentication:

class GrapeTokenAuthDemo < Grape::API
  format :json

  include GrapeTokenAuth::MountHelpers

  # ...
end

This allows us to mount the authentication endpoints as so:

class GrapeTokenAuthDemo < Grape::API
  # ...

  mount_registration(to: '/auth', for: :user)
  mount_sessions(to: '/auth', for: :user)
  mount_token_validation(to: '/auth', for: :user)

  # ...
end

Meaning for each API we are mounting: /auth is relative to wherever GrapeTokenAuthDemo is mounted. Remember, we are just running GrapeTokenAuthDemo as the main rack app so it is the root and registration/sessions/token_validation will be at /auth. We are also defining the scope that is being mounted (user) which we previously mapped in the configuration step.

The authentication APIs are now mounted for registering a user by email. There are several other APIs available (including omniauth), see the demo repo for a full example.

Authenticating the endpoint

In order to have access to the authentication helpers, we must include the TokenAuthentication module in the Grape API like so:

class GrapeTokenAuthDemo < Grape::API
  # ...

  include GrapeTokenAuth::TokenAuthentication

  # ...
end

Unlike MountHelpers you will want to include this in any grape app where you want to use the authentication.

We can protect a given endpoint by calling authenticate_user! within the endpoint. If the user does not present valid authentication credentials, execution will stop and a 403 response will be returned. We can also take advantage of the current_user helper to present the user’s email in the response:

get '/protected_endpoint' do
  authenticate_user!
  status 200
  response = { message: "Welcome #{current_user.email}",
                user: current_user }
  present(data: response)
end

With this step complete, we now have all parts of authentication setup. Users can be setup and authenticated by hitting the registration and session API endpoints respectively. This, of course, is all made easier with ng-token-auth or j-toker, refer to the demo repo to see a complete example.

Thanks for reading and please let me know of any questions in the comments or via twitter.

comments powered by Disqus