Skip to content

Instantly share code, notes, and snippets.

@theCrab
Last active April 27, 2022 15:42
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save theCrab/54a339b7a08ddad84e35 to your computer and use it in GitHub Desktop.
Save theCrab/54a339b7a08ddad84e35 to your computer and use it in GitHub Desktop.
A Hanami Framework authentication based on JSON Web Tokens.
# lib/authentications/authentication.rb
# @api auth
# Authentication base class
#
module Authentication
def self.included(base)
base.class_eval do
before :authenticate!
expose :current_user
end
end
def authenticate!
halt 401 unless authenticated?
end
def current_user
@current_user ||= authenticate_user
end
private
def authenticated?
!!current_user
end
def authenticate_user
# Every api request has an access_token in the header
# Find the user and verify they exist
jwt = JWT.decode(payload, HANAMI_ENV['HMAC_SECRET'], algorithm: 'HS256')
#user = User.with_token(headers['Authentication'])
user = UserRepository.find(jwt.user_id)
if user && !user.revoked
return @current_user = user
end
end
end
# apps/web/controllers/sessions/create.rb
require 'jwt'
module Web
module Controllers
module Sessions
class Create
include Web::Action
accept :json
params do
param :username, type: String, presence: true
param :password, type: String, presence: true
end
def call(params)
halt 422 unless params.valid?
login
end
def login
user = UserRepository.find_by_username(params[:username])
halt 401 unless user
halt 403 unless valid_password?(user.password_hash)
options = { iss: 'http://hanamirb.org/', exp: 804700, user_id: user.id, audience: 'github' }
token = JWT.encode(options, HANAMI_ENV['HMAC_SECRET'], algorithm: 'HS256')
response.status = 200
response.body = { access_token: token, user: user, .... }.to_json
end
def authenticate!
# Nothing to see here, move along.
end
private
def valid_password?(password)
BCrypt::Password.new(params[:password]) == password
end
end
end
end
end

This is an attempt to get this project going. It's long overdue. This project is meant to be simple and plugable. Hanami is growing and at some point the one thing holding developers back is the User Authentication. So we need to cover this area so we move forward quick. This should be a community effort. A basic agnostic barebones gem that you can build on.

Mantra

JSON First.

This project requires gem 'jwt'

Features

  • login
  • recover_password
  • current_user
  • revoke_access
#lib/app_name/entities/user.rb
class User
include Hanami::Entity
attributes :username, :password_hash, :email, :access_token, :revoked, :pw_recovery_token, :created_at, :updated_at
def with_token(token)
token = token.sub('Bearer ', '').strip
UserRepository.find_by_access_token(token) # TODO: We actually do not need to persist this token in the db. Enc/Decode with JWT
end
end
@michalvalasek
Copy link

Hey Mr. Crab,

  1. Is your intention to make it token only auth or are you considering making it configurable token/session so that it's usable (or more accessible for beginners) for traditional web apps too?
  2. I would extract the login method to the Auth module (username, password -> token).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment