Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions app/controllers/api_guard/authentication_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@ class AuthenticationController < ApplicationController

def create
if resource.authenticate(params[:password])
create_token_and_set_header(resource, resource_name)
render_success(message: I18n.t('api_guard.authentication.signed_in'))
create_and_set_token_pair(resource, resource_name)
render_success(data: resource, message: I18n.t('api_guard.authentication.signed_in'))
else
render_error(422, message: I18n.t('api_guard.authentication.invalid_login_credentials'))
end
end

def destroy
blacklist_token
remove_tokens_from_cookies
render_success(message: I18n.t('api_guard.authentication.signed_out'))
end

Expand Down
2 changes: 1 addition & 1 deletion app/controllers/api_guard/passwords_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def update
blacklist_token unless ApiGuard.invalidate_old_tokens_on_password_change
destroy_all_refresh_tokens(current_resource)

create_token_and_set_header(current_resource, resource_name)
create_and_set_token_pair(current_resource, resource_name)
render_success(message: I18n.t('api_guard.password.changed'))
else
render_error(422, object: current_resource)
Expand Down
7 changes: 4 additions & 3 deletions app/controllers/api_guard/registration_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,17 @@ class RegistrationController < ApplicationController
def create
init_resource(sign_up_params)
if resource.save
create_token_and_set_header(resource, resource_name)
render_success(message: I18n.t('api_guard.registration.signed_up'))
create_and_set_token_pair(resource, resource_name)
render_success(data: resource, message: I18n.t('api_guard.registration.signed_up'))
else
render_error(422, object: resource)
end
end

def destroy
current_resource.destroy
render_success(message: I18n.t('api_guard.registration.account_deleted'))
remove_tokens_from_cookies
render_success(data: nil, message: I18n.t('api_guard.registration.account_deleted'))
end

private
Expand Down
14 changes: 9 additions & 5 deletions app/controllers/api_guard/tokens_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class TokensController < ApplicationController
before_action :find_refresh_token, only: [:create]

def create
create_token_and_set_header(current_resource, resource_name)
create_and_set_token_pair(current_resource, resource_name)

@refresh_token.destroy
blacklist_token if ApiGuard.blacklist_token_after_refreshing
Expand All @@ -19,10 +19,14 @@ def create
private

def find_refresh_token
refresh_token_from_header = request.headers['Refresh-Token']

if refresh_token_from_header
@refresh_token = find_refresh_token_of(current_resource, refresh_token_from_header)
refresh_token_from_request = if ApiGuard.enable_tokens_in_cookies
request.cookies['refresh_token']
else
request.headers['Refresh-Token']
end

if refresh_token_from_request
@refresh_token = find_refresh_token_of(current_resource, refresh_token_from_request)
return render_error(401, message: I18n.t('api_guard.refresh_token.invalid')) unless @refresh_token
else
render_error(401, message: I18n.t('api_guard.refresh_token.missing'))
Expand Down
3 changes: 3 additions & 0 deletions lib/api_guard.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ module Test
{}
end

mattr_accessor :enable_tokens_in_cookies
self.enable_tokens_in_cookies = false

def self.setup
yield self
end
Expand Down
7 changes: 6 additions & 1 deletion lib/api_guard/jwt_auth/authentication.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ def respond_to_missing?(method_name, include_private = false)
def authenticate_and_set_resources(resource_names)
@resource_names = resource_names

@token = request.headers['Authorization']&.split('Bearer ')&.last
@token = if ApiGuard.enable_tokens_in_cookies
request.cookies['access_token']
else
request.headers['Authorization']&.split('Bearer ')&.last
end

return render_error(401, message: I18n.t('api_guard.access_token.missing')) unless @token

authenticate_token
Expand Down
59 changes: 52 additions & 7 deletions lib/api_guard/jwt_auth/json_web_token.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,12 @@ def current_time
@current_time ||= Time.now.utc
end

def token_expire_at
@token_expire_at ||= (current_time + ApiGuard.token_validity).to_i
def access_token_expire_at
@token_expire_at ||= (current_time + ApiGuard.token_validity)
end

def refresh_token_expire_at
@refresh_token_expire_at_date ||= (Time.now.utc + ApiGuard.refresh_token_validity)
end

def token_issued_at
Expand All @@ -38,7 +42,7 @@ def decode(token, verify = true)
def jwt_and_refresh_token(resource, resource_name, expired_token = false, expired_refresh_token = false)
payload = {
"#{resource_name}_id": resource.id,
exp: expired_token ? token_issued_at : token_expire_at,
exp: expired_token ? token_issued_at : access_token_expire_at.to_i,
iat: token_issued_at
}

Expand All @@ -48,17 +52,58 @@ def jwt_and_refresh_token(resource, resource_name, expired_token = false, expire
[encode(payload), new_refresh_token(resource, expired_refresh_token)]
end

# Create tokens and set response headers
def create_token_and_set_header(resource, resource_name)
# Create tokens and set response headers and cookies
def create_and_set_token_pair(resource, resource_name)
access_token, refresh_token = jwt_and_refresh_token(resource, resource_name)
set_token_headers(access_token, refresh_token)

if ApiGuard.enable_tokens_in_cookies
set_token_cookies(access_token, refresh_token)
else
set_token_headers(access_token, refresh_token)
end
end

# Set token details in response headers
def set_token_headers(token, refresh_token = nil)
response.headers['Access-Token'] = token
response.headers['Refresh-Token'] = refresh_token if refresh_token
response.headers['Expire-At'] = token_expire_at.to_s
response.headers['Expire-At'] = access_token_expire_at.to_i.to_s
end

def set_token_cookies(access_token, refresh_token)
response.set_cookie(
'access_token',
{
value: access_token,
http_only: true,
expires: refresh_token_expire_at,
path: '/'
}
)
response.set_cookie(
'refresh_token',
{
value: refresh_token,
http_only: true,
expires: refresh_token_expire_at,
path: '/'
}
)
end

def remove_tokens_from_cookies
response.delete_cookie(
'access_token',
{
path: '/'
}
)
response.delete_cookie(
'refresh_token',
{
path: '/'
}
)
end

# Set token issued at to current timestamp
Expand Down