From 6f3c6cfb11ceb3ce4df88e069981e119aaa7abc1 Mon Sep 17 00:00:00 2001 From: hassantarif Date: Sun, 9 Oct 2022 19:52:22 +0100 Subject: [PATCH 1/2] adding the implemention of cookies only, but I am not sure why when I try to write tests and run them, nothing shows --- Gemfile.lock | 8 ++--- .../api_guard/tokens_controller.rb | 6 +++- lib/api_guard.rb | 12 +++++++ lib/api_guard/jwt_auth/authentication.rb | 7 +++- lib/api_guard/jwt_auth/json_web_token.rb | 36 +++++++++++++++++++ lib/api_guard/jwt_auth/refresh_jwt_token.rb | 1 + lib/api_guard/response_formatters/renderer.rb | 6 +++- .../templates/tokens_controller.rb | 6 +++- 8 files changed, 74 insertions(+), 8 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 5032e56..e75215c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -75,7 +75,7 @@ GEM factory_bot_rails (6.1.0) factory_bot (~> 6.1.0) railties (>= 5.0.0) - ffi (1.13.1) + ffi (1.15.5) globalid (0.4.2) activesupport (>= 4.2.0) i18n (1.8.5) @@ -83,7 +83,7 @@ GEM jaro_winkler (1.5.4) json (2.3.1) jwt (2.2.2) - listen (3.2.1) + listen (3.7.1) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) loofah (2.7.0) @@ -139,7 +139,7 @@ GEM thor (>= 0.20.3, < 2.0) rainbow (3.0.0) rake (13.0.1) - rb-fsevent (0.10.4) + rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) rspec-core (3.9.2) @@ -205,4 +205,4 @@ DEPENDENCIES sqlite3 (~> 1.4) BUNDLED WITH - 2.1.4 + 2.3.7 diff --git a/app/controllers/api_guard/tokens_controller.rb b/app/controllers/api_guard/tokens_controller.rb index 8c621fe..5949059 100644 --- a/app/controllers/api_guard/tokens_controller.rb +++ b/app/controllers/api_guard/tokens_controller.rb @@ -19,7 +19,11 @@ def create private def find_refresh_token - refresh_token_from_header = request.headers['Refresh-Token'] + if ApiGuard.enable_response_headers + refresh_token_from_header = request.headers['Refresh-Token'] + elsif ApiGuard.enable_cookies_response + refresh_token_from_header = request.cookies.signed[:kebbah] + end if refresh_token_from_header @refresh_token = find_refresh_token_of(current_resource, refresh_token_from_header) diff --git a/lib/api_guard.rb b/lib/api_guard.rb index 043b0cd..ee5a1dd 100644 --- a/lib/api_guard.rb +++ b/lib/api_guard.rb @@ -11,6 +11,18 @@ module Test autoload :ControllerHelper, 'api_guard/test/controller_helper' end + mattr_accessor :enable_response_headers + self.enable_response_headers = true + + mattr_accessor :add_domain_for_refresh_token + self.add_domain_for_refresh_token = nil + + mattr_accessor :enable_response_body + self.enable_response_body = false + + mattr_accessor :enable_cookies_response + self.enable_cookies_response = false + mattr_accessor :token_validity self.token_validity = 1.day diff --git a/lib/api_guard/jwt_auth/authentication.rb b/lib/api_guard/jwt_auth/authentication.rb index 0593f07..94bec64 100644 --- a/lib/api_guard/jwt_auth/authentication.rb +++ b/lib/api_guard/jwt_auth/authentication.rb @@ -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 + if ApiGuard.enable_response_headers + @token = request.headers['Authorization']&.split('Bearer ')&.last + elsif ApiGuard.enable_cookies_response + @token = request.cookies.signed[:access_token][:access_token] + end + return render_error(401, message: I18n.t('api_guard.access_token.missing')) unless @token authenticate_token diff --git a/lib/api_guard/jwt_auth/json_web_token.rb b/lib/api_guard/jwt_auth/json_web_token.rb index 0af33f9..894fb81 100644 --- a/lib/api_guard/jwt_auth/json_web_token.rb +++ b/lib/api_guard/jwt_auth/json_web_token.rb @@ -45,6 +45,7 @@ def jwt_and_refresh_token(resource, resource_name, expired_token = false, expire # Add custom data in the JWT token payload payload.merge!(resource.jwt_token_payload) if resource.respond_to?(:jwt_token_payload) + # generate the access token and refresh token [encode(payload), new_refresh_token(resource, expired_refresh_token)] end @@ -54,6 +55,16 @@ def create_token_and_set_header(resource, resource_name) set_token_headers(access_token, refresh_token) end + def create_token_and_set_in_strategy(resource, resource_name) + access_token, refresh_token = jwt_and_refresh_token(resource, resource_name) + + if ApiGuard.enable_response_headers + set_token_headers(access_token, refresh_token) + elsif ApiGuard.enable_cookies_response + set_token_cookies(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 @@ -61,6 +72,31 @@ def set_token_headers(token, refresh_token = nil) response.headers['Expire-At'] = token_expire_at.to_s end + def set_token_cookies(token, refresh_token) + # the secure way is just storing the refresh token in the cookies + # and leave the access token in the headers, but in your frontend, + # you need to make a accessor to the a variable called access token + # you can do this approche, or just store access token and refresh + # token in the headers + cookies.signed[:access_token] = { + value: { access_token: access_token, expires_at: token_expire_at.to_s}, + http_only: true, + expires: ApiGuard.token_validity, + domain: ApiGuard.add_domain_for_refresh_token, + secure: true, + same_site: 'strict' + } + + cookies.signed[:kebbah] = { + value: refresh_token, + http_only: true, + expires: ApiGuard.refresh_token_validity, + domain: ApiGuard.add_domain_for_refresh_token, + secure: true, + same_site: 'strict' + } if refresh_token + end + # Set token issued at to current timestamp # to restrict access to old access(JWT) tokens def invalidate_old_jwt_tokens(resource) diff --git a/lib/api_guard/jwt_auth/refresh_jwt_token.rb b/lib/api_guard/jwt_auth/refresh_jwt_token.rb index 9454ee7..3bae577 100644 --- a/lib/api_guard/jwt_auth/refresh_jwt_token.rb +++ b/lib/api_guard/jwt_auth/refresh_jwt_token.rb @@ -47,6 +47,7 @@ def destroy_all_refresh_tokens(resource) refresh_tokens_for(resource).destroy_all end + end end end diff --git a/lib/api_guard/response_formatters/renderer.rb b/lib/api_guard/response_formatters/renderer.rb index b0e06f8..efea65c 100644 --- a/lib/api_guard/response_formatters/renderer.rb +++ b/lib/api_guard/response_formatters/renderer.rb @@ -5,8 +5,8 @@ module ResponseFormatters module Renderer def render_success(data: nil, message: nil) resp_data = { status: I18n.t('api_guard.response.success') } - resp_data[:message] = message if message resp_data[:data] = data if data + resp_data[:message] = message if message render json: resp_data, status: 200 end @@ -20,3 +20,7 @@ def render_error(status, options = {}) end end end + +class App + mattr_accessor :message +end \ No newline at end of file diff --git a/lib/generators/api_guard/controllers/templates/tokens_controller.rb b/lib/generators/api_guard/controllers/templates/tokens_controller.rb index 0e861a0..d3f1590 100644 --- a/lib/generators/api_guard/controllers/templates/tokens_controller.rb +++ b/lib/generators/api_guard/controllers/templates/tokens_controller.rb @@ -15,7 +15,11 @@ class TokensController < ApiGuard::TokensController # private # def find_refresh_token - # refresh_token_from_header = request.headers['Refresh-Token'] + # if ApiGuard.enable_response_headers + # refresh_token_from_header = request.headers['Refresh-Token'] + # elsif ApiGuard.enable_cookies_response + # refresh_token_from_header = request.cookies.signed[:kebbah] + # end # # if refresh_token_from_header # @refresh_token = find_refresh_token_of(current_resource, refresh_token_from_header) From acb38ced675117cddf237b4e7c09c0a9908d5be6 Mon Sep 17 00:00:00 2001 From: hassantarif Date: Sun, 9 Oct 2022 19:58:26 +0100 Subject: [PATCH 2/2] find refresh token --- app/controllers/api_guard/tokens_controller.rb | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/app/controllers/api_guard/tokens_controller.rb b/app/controllers/api_guard/tokens_controller.rb index 5949059..5aca629 100644 --- a/app/controllers/api_guard/tokens_controller.rb +++ b/app/controllers/api_guard/tokens_controller.rb @@ -19,12 +19,19 @@ def create private def find_refresh_token - if ApiGuard.enable_response_headers + unless ApiGuard.enable_cookies_response refresh_token_from_header = request.headers['Refresh-Token'] - elsif ApiGuard.enable_cookies_response - refresh_token_from_header = request.cookies.signed[:kebbah] - end + if refresh_token_from_header + @refresh_token = find_refresh_token_of(current_resource, refresh_token_from_header) + 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')) + end + + end + + refresh_token_from_header = request.cookies.signed[:kebbah] if refresh_token_from_header @refresh_token = find_refresh_token_of(current_resource, refresh_token_from_header) return render_error(401, message: I18n.t('api_guard.refresh_token.invalid')) unless @refresh_token