Skip to content

Commit b66920d

Browse files
committed
add cookies as storing options for tokens
1 parent f0a82c1 commit b66920d

7 files changed

+97
-21
lines changed

app/controllers/api_guard/authentication_controller.rb

+3-2
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,16 @@ class AuthenticationController < ApplicationController
99

1010
def create
1111
if resource.authenticate(params[:password])
12-
create_token_and_set_header(resource, resource_name)
13-
render_success(message: I18n.t('api_guard.authentication.signed_in'))
12+
create_and_set_token_pair(resource, resource_name)
13+
render_success(data: resource, message: I18n.t('api_guard.authentication.signed_in'))
1414
else
1515
render_error(422, message: I18n.t('api_guard.authentication.invalid_login_credentials'))
1616
end
1717
end
1818

1919
def destroy
2020
blacklist_token
21+
remove_tokens_from_cookies
2122
render_success(message: I18n.t('api_guard.authentication.signed_out'))
2223
end
2324

app/controllers/api_guard/passwords_controller.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ def update
1313
blacklist_token unless ApiGuard.invalidate_old_tokens_on_password_change
1414
destroy_all_refresh_tokens(current_resource)
1515

16-
create_token_and_set_header(current_resource, resource_name)
16+
create_and_set_token_pair(current_resource, resource_name)
1717
render_success(message: I18n.t('api_guard.password.changed'))
1818
else
1919
render_error(422, object: current_resource)

app/controllers/api_guard/registration_controller.rb

+4-3
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,17 @@ class RegistrationController < ApplicationController
99
def create
1010
init_resource(sign_up_params)
1111
if resource.save
12-
create_token_and_set_header(resource, resource_name)
13-
render_success(message: I18n.t('api_guard.registration.signed_up'))
12+
create_and_set_token_pair(resource, resource_name)
13+
render_success(data: resource, message: I18n.t('api_guard.registration.signed_up'))
1414
else
1515
render_error(422, object: resource)
1616
end
1717
end
1818

1919
def destroy
2020
current_resource.destroy
21-
render_success(message: I18n.t('api_guard.registration.account_deleted'))
21+
remove_tokens_from_cookies
22+
render_success(data: nil, message: I18n.t('api_guard.registration.account_deleted'))
2223
end
2324

2425
private

app/controllers/api_guard/tokens_controller.rb

+28-7
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,50 @@
44

55
module ApiGuard
66
class TokensController < ApplicationController
7-
before_action :authenticate_resource, only: [:create]
87
before_action :find_refresh_token, only: [:create]
98

109
def create
11-
create_token_and_set_header(current_resource, resource_name)
10+
create_and_set_token_pair(current_resource, resource_name)
1211

1312
@refresh_token.destroy
14-
blacklist_token if ApiGuard.blacklist_token_after_refreshing
13+
blacklist_token if ApiGuard.blacklist_token_after_refreshing && access_token
1514

1615
render_success(message: I18n.t('api_guard.access_token.refreshed'))
1716
end
1817

1918
private
2019

2120
def find_refresh_token
22-
refresh_token_from_header = request.headers['Refresh-Token']
23-
24-
if refresh_token_from_header
25-
@refresh_token = find_refresh_token_of(current_resource, refresh_token_from_header)
21+
refresh_token_from_request = if ApiGuard.enable_tokens_in_cookies
22+
request.cookies['refresh_token']
23+
else
24+
request.headers['Refresh-Token']
25+
end
26+
27+
if refresh_token_from_request
28+
@refresh_token = RefreshToken.find_by(token: refresh_token_from_request)
2629
return render_error(401, message: I18n.t('api_guard.refresh_token.invalid')) unless @refresh_token
2730
else
2831
render_error(401, message: I18n.t('api_guard.refresh_token.missing'))
2932
end
3033
end
34+
35+
def access_token
36+
@access_token ||= if ApiGuard.enable_tokens_in_cookies
37+
request.cookies['access_token']
38+
else
39+
request.headers['Authorization']&.split('Bearer ')&.last
40+
end
41+
end
42+
43+
def current_resource
44+
@current_resource ||= @refresh_token.send(resource_name)
45+
end
46+
47+
def blacklist_token
48+
return unless token_blacklisting_enabled?(current_resource)
49+
50+
blacklisted_tokens_for(current_resource).create(token: access_token)
51+
end
3152
end
3253
end

lib/api_guard.rb

+3
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ module Test
3333
{}
3434
end
3535

36+
mattr_accessor :enable_tokens_in_cookies
37+
self.enable_tokens_in_cookies = false
38+
3639
def self.setup
3740
yield self
3841
end

lib/api_guard/jwt_auth/authentication.rb

+6-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,12 @@ def respond_to_missing?(method_name, include_private = false)
2424
def authenticate_and_set_resources(resource_names)
2525
@resource_names = resource_names
2626

27-
@token = request.headers['Authorization']&.split('Bearer ')&.last
27+
@token = if ApiGuard.enable_tokens_in_cookies
28+
request.cookies['access_token']
29+
else
30+
request.headers['Authorization']&.split('Bearer ')&.last
31+
end
32+
2833
return render_error(401, message: I18n.t('api_guard.access_token.missing')) unless @token
2934

3035
authenticate_token

lib/api_guard/jwt_auth/json_web_token.rb

+52-7
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,12 @@ def current_time
1010
@current_time ||= Time.now.utc
1111
end
1212

13-
def token_expire_at
14-
@token_expire_at ||= (current_time + ApiGuard.token_validity).to_i
13+
def access_token_expire_at
14+
@token_expire_at ||= (current_time + ApiGuard.token_validity)
15+
end
16+
17+
def refresh_token_expire_at
18+
@refresh_token_expire_at_date ||= (Time.now.utc + ApiGuard.refresh_token_validity)
1519
end
1620

1721
def token_issued_at
@@ -38,7 +42,7 @@ def decode(token, verify = true)
3842
def jwt_and_refresh_token(resource, resource_name, expired_token = false, expired_refresh_token = false)
3943
payload = {
4044
"#{resource_name}_id": resource.id,
41-
exp: expired_token ? token_issued_at : token_expire_at,
45+
exp: expired_token ? token_issued_at : access_token_expire_at.to_i,
4246
iat: token_issued_at
4347
}
4448

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

51-
# Create tokens and set response headers
52-
def create_token_and_set_header(resource, resource_name)
55+
# Create tokens and set response headers and cookies
56+
def create_and_set_token_pair(resource, resource_name)
5357
access_token, refresh_token = jwt_and_refresh_token(resource, resource_name)
54-
set_token_headers(access_token, refresh_token)
58+
59+
if ApiGuard.enable_tokens_in_cookies
60+
set_token_cookies(access_token, refresh_token)
61+
else
62+
set_token_headers(access_token, refresh_token)
63+
end
5564
end
5665

5766
# Set token details in response headers
5867
def set_token_headers(token, refresh_token = nil)
5968
response.headers['Access-Token'] = token
6069
response.headers['Refresh-Token'] = refresh_token if refresh_token
61-
response.headers['Expire-At'] = token_expire_at.to_s
70+
response.headers['Expire-At'] = access_token_expire_at.to_i.to_s
71+
end
72+
73+
def set_token_cookies(access_token, refresh_token)
74+
response.set_cookie(
75+
'access_token',
76+
{
77+
value: access_token,
78+
http_only: true,
79+
expires: refresh_token_expire_at,
80+
path: '/'
81+
}
82+
)
83+
response.set_cookie(
84+
'refresh_token',
85+
{
86+
value: refresh_token,
87+
http_only: true,
88+
expires: refresh_token_expire_at,
89+
path: '/'
90+
}
91+
)
92+
end
93+
94+
def remove_tokens_from_cookies
95+
response.delete_cookie(
96+
'access_token',
97+
{
98+
path: '/'
99+
}
100+
)
101+
response.delete_cookie(
102+
'refresh_token',
103+
{
104+
path: '/'
105+
}
106+
)
62107
end
63108

64109
# Set token issued at to current timestamp

0 commit comments

Comments
 (0)