JWT Keeper
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
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.