Skip to content

Instantly share code, notes, and snippets.

@joshgoebel
Forked from evadne/ephemeral_token.rb
Created December 16, 2015 22:04
Show Gist options
  • Save joshgoebel/ab24afc0eba92db79925 to your computer and use it in GitHub Desktop.
Save joshgoebel/ab24afc0eba92db79925 to your computer and use it in GitHub Desktop.
Ephemeral Secure Token with JWT
class EphemeralToken
attr_reader :origin, :targets, :expires_at, :payload
class TokenInvalid < StandardError; end
class TokenExpired < TokenInvalid; end
Algorithm = 'HS512'
Secret = ENV['SECRET_EPHEMERAL_TOKEN_KEY']
ObjectToNotation = -> (target) { [target.class.model_name.name, target.id] }
NotationToObject = -> ((model_name, model_id)) { model_name.constantize.find_by_id(model_id) }
class << self
def parse (token)
payload, _ = decode_jwt(token)
data, exp = payload.values_at('data', 'exp')
new({
origin: data['origin'].try(&NotationToObject),
targets: data['targets'].map(&NotationToObject).compact,
expires_at: exp.try { |x| Time.at(x) }
})
end
private
def decode_jwt (token)
JWT.decode(token, Secret)
rescue JWT::ExpiredSignature
raise TokenExpired.new 'the token has expired'
rescue JWT::DecodeError
raise TokenInvalid.new 'the token is not valid'
end
end
def initialize (origin: nil, targets: [], expires_at: nil)
@origin = origin
@targets = Array(targets)
@expires_at = expires_at
end
def payload
@payload ||= build_payload
end
def to_jwt
JWT.encode payload, Secret, Algorithm
end
def has_target? (target)
targets.any? { |x|
(x.id == target.id) && (x.class.model_name.name == target.class.model_name.name)
}
end
private
def build_payload
{
data: {
origin: origin.try(&ObjectToNotation),
targets: targets.map(&ObjectToNotation)
}
}.tap { |x|
if expires_at.present?
x[:exp] = expires_at.to_time.to_i
end
}
end
end
module Concerns::HasPreviewToken
extend ActiveSupport::Concern
def authorize_preview! (target)
unless preview_token.has_target?(target)
deny_preview
end
rescue EphemeralToken::TokenInvalid
deny_preview
end
def deny_preview
raise CanCan::AccessDenied.new('you are not authorized to view this page.')
end
def preview_token
@preview_token ||= EphemeralToken.parse(params[:preview_token])
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment