Setting up authentication on a Grape API with GrapeTokenAuth
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:
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.