ben tedder : code things

Part 3: Create a Rails 5 API with JWT's (jsonwebtoken)

Step 1. Install Rails 5

gem install rails --version 5.0.0

Step 2. Create a new Rails 5 API and start it up

Now we're going to generate a new Rails app with the --api flag (see Using Rails for API-only Applications on the Rails Guides)

rails new my-api --api
cd my-api
rails s

Step 3. Create a new /api route

Use the rails generator to create a new controller

rails g new controller api

in controllers/api_controller.rb add a method:

def index
  render json: { message: 'our api!' }
end

in config/routes.rb create a new route to hit that controller method

get '/api', to: 'api#index'

Step 4. Create a post route that creates a JWT

First, let's grab the ruby jwt gem: Put gem 'jwt' in your Gemfile, kill your server, run bundle install and restart your server

Edit your api_controller.rb to include the jwt gem:

class ApiController < ApplicationController
  require 'jwt'

Now, similar to the node.js / express implementation we're going to create a route that can be POSTed to.

In controllers/api_controller create a new method called login

def login
  current_user = { id: 3 }
  secret = 'my_secret_key'
  token = JWT.encode(current_user, secret, 'HS256')
  render json: {
    token: token
  }
end

Don't forget to create a route to listen for a POST in config/routes.rb

post '/api/login', to: 'api#login'

Step 5. POST to your route and get a token

Start up Postman and send a POST request to http://localhost:3000/api/login. You should receive a token. Copy that token. You'll use it in a second.

Step 6. Create a protected route

Now we need to create a route that needs a verified token in order to continue.

In config/routes.rb create a new protected route:

get '/api/secret', to: 'api#secret'

And in your controller create a method called secret, as well as a helper method to strip out the token from the Authorization header.

def secret
  secret = 'my_secret_key'
  token = bearer_token || nil
  begin
    decoded_token = JWT.decode(token, secret, true, { :algorithm => 'HS256' })
    if decoded_token
      render json: { message: 'you found the secret!' }
    else
      render json: { message: 'get out of here'}, status: 403
    end
  rescue
    render json: { message: 'error with your token' }, status: 403
  end
end

def bearer_token
  pattern = /^Bearer /
  header  = request.headers["Authorization"]
  header.gsub(pattern, '') if header && header.match(pattern)
end

Step 7. Test it out!

  • Open up Postman, get a token by sending a POST request to /api/login
  • Create a GET request to /api/secret with an "Authorization" header with a value of "Bearer yourtoken.goes.here"

And that's it! Use that token for every request you make from your front-end code, and your API will be able to decode the token, realize which user is requesting the resource, and act accordingly. If you want to store more on the token (ie, the user's role), go for it.