JWT Keeper

Gem Version Build Status Dependency Status Code Climate Test Coverage Inline docs

An managing interface layer for handling the creation and validation of JWTs.

Setup

  • Add gem 'jwt_keeper' to Gemfile
  • Run rails generate keeper:install
  • Configure config/initializers/jwt_keeper.rb
  • Done

Basic Usage

Here are the basic methods you can call to perform various operations

token = JWTKeeper::Token.create(private_claim_hash)
token = JWTKeeper::Token.find(raw_token_string)

token.revoke
token.rotate

token.valid?
raw_token_string = token.to_jwt

Rails Usage

The designed rails token flow is to receive and respond to requests with the token being present in the Authorization part of the header. This is to allow us to seamlessly rotate the tokens on the fly without having to rebuff the request as part of the user flow. Automatic rotation happens as part of the require_authentication action, meaning that you will always get the latest token data as created by generate_claims in your controllers. This new token is added to the response with the write_authentication_token action.

rails generate jwt_keeper:install
class ApplicationController < ActionController::Base
  include JWTKeeper::Controller

  before_action :require_authentication
  rescue_from JWTKeeper::NotAuthenticatedError, with: :not_authenticated

  def not_authenticated
    # Overload to return status 401
  end

  def authenticated(token)
    # Overload to make use of token data
  end

  def regenerate_claims(old_token)
    # Overload to update claims on automatic rotation.
    current_user = User.find(old_token.claims[:uid])
    { uid: current_user.id, usn: current_user.email }
  end
end
class SessionsController < ApplicationController
  skip_before_action :require_authentication, only: :create

  # POST /sessions
  def create
    token = JWTKeeper::Token.create(uid: @user.id, usn: @user.email)
    write_authentication_token(token)
  end

  # PATCH/PUT /sessions
  def update
    token = read_authentication_token
    token.rotate
    write_authentication_token(token)
  end

  # DELETE /sessions
  def destroy
    token = read_authentication_token
    token.revoke
    clear_authentication_token
  end

Invalidation

Hard Invalidation

Hard Invalidation is a permanent revocation of the token. The primary cases of this is when a user wishes to logout, or when your security has been otherwise compromised. To revoke all tokens simply update the configuration secret. To revoke a single token you can utilize either the class(Token.revoke(jti)) or instance(token.revoke) method.

Soft Invalidation

Soft Invalidation is the process of triggering a rotation upon the next time a token is seen in a request. On the global scale this is done when there is a version mismatch in the config. Utilizing the rails controller flow, this method works even if you have two different versions of your app deployed and requests bounce back and forth; Making rolling deployments and rollbacks completely seamless. To rotate a single token, like in the case of a change of user permissions, simply use the class(Token.rotate) method to flag the token for regeneration.

Cookie locking is the practice of securing the JWT by pairing it with a secure/httponly cookie. When a JWT is created, part of the secret used to sign it is a one time generated key that is stored in a matching cookie. The cookie and JWT thus must be sent together to be considered valid. The effective result makes it extremely hard to hijack a session by stealing the JWT. This reduces the surface area of XSS considerably.