Skip to content

Commit

Permalink
encrypt session_token
Browse files Browse the repository at this point in the history
  • Loading branch information
lazaronixon committed Feb 18, 2022
1 parent e4964be commit c942a36
Show file tree
Hide file tree
Showing 6 changed files with 18 additions and 22 deletions.
15 changes: 10 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ The purpose of authentication zero is to generate a pre-built authentication sys

## Security and best practices

- [Current attributes](https://api.rubyonrails.org/classes/ActiveSupport/CurrentAttributes.html): Abstract super class that provides a thread-isolated attributes singleton, which resets automatically before and after each request.
- [has_secure_password](https://api.rubyonrails.org/classes/ActiveModel/SecurePassword/ClassMethods.html#method-i-has_secure_password): Adds methods to set and authenticate against a BCrypt password.
- [has_secure_token](https://api.rubyonrails.org/classes/ActiveRecord/SecureToken/ClassMethods.html#method-i-has_secure_token): Adds methods to generate unique tokens.
- [encrypts](https://guides.rubyonrails.org/active_record_encryption.html) Encrypts the session_token on database so if an attacker gained access to your database, a snapshot of it, or your application logs, they wouldn't be able to make sense of the encrypted information.
- [httponly cookies](https://api.rubyonrails.org/classes/ActionDispatch/Cookies.html): A cookie with the httponly attribute is inaccessible to the JavaScript, this precaution helps mitigate cross-site scripting (XSS) attacks.
- [signed_id](https://api.rubyonrails.org/classes/ActiveRecord/SignedId.html): Returns a signed id that is tamper proof, so it's safe to send in an email or otherwise share with the outside world.
- [Signed cookies](https://api.rubyonrails.org/classes/ActionDispatch/Cookies.html): Returns a jar that'll automatically generate a signed representation of cookie value and verify it when reading from the cookie again.
- [Http only cookies](https://api.rubyonrails.org/classes/ActionDispatch/Cookies.html): A cookie with the httponly attribute is inaccessible to the JavaScript, this precaution helps mitigate cross-site scripting (XSS) attacks.
- [Log filtering](https://guides.rubyonrails.org/action_controller_overview.html#log-filtering): Parameters 'token' and 'password' are marked [FILTERED] in the log.
- [Current Attributes](https://api.rubyonrails.org/classes/ActiveSupport/CurrentAttributes.html): Abstract super class that provides a thread-isolated attributes singleton, which resets automatically before and after each request.
- [Log Filtering](https://guides.rubyonrails.org/action_controller_overview.html#log-filtering): Parameters 'token' and 'password' are marked [FILTERED] in the log.
- [Callbacks](https://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html): We use callbacks to send emails after changing an email or password.
- [Action mailer](https://api.rubyonrails.org/classes/ActionMailer/Base.html): Action Mailer allows you to send email from your application using a mailer model and views.
- [Action Mailer](https://api.rubyonrails.org/classes/ActionMailer/Base.html): Action Mailer allows you to send email from your application using a mailer model and views.

## Installation

Expand All @@ -38,6 +38,11 @@ gem "authentication-zero"

Then run `bundle install`

You'll need to set up active record encryption, run the command below and follow the instructions.
```
$ rails db:encryption:init
```

You'll need to set the root path in your routes.rb, for this example let's use the following:

```ruby
Expand Down
4 changes: 2 additions & 2 deletions lib/generators/authentication/authentication_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def add_application_controller_methods
private
def authenticate
if #{singular_table_name} = authenticate_with_http_token { |t, _| #{class_name}.find_signed_session_token(t) }
if #{singular_table_name} = authenticate_with_http_token { |t, _| #{class_name}.find_by_session_token(t) }
Current.#{singular_table_name} = #{singular_table_name}
else
request_http_token_authentication
Expand All @@ -73,7 +73,7 @@ def authenticate
private
def authenticate
if #{singular_table_name} = #{class_name}.find_by_session_token(cookies.signed[:session_token])
if #{singular_table_name} = #{class_name}.find_by_session_token(cookies[:session_token])
Current.#{singular_table_name} = #{singular_table_name}
else
redirect_to sign_in_path, alert: "You need to sign in or sign up before continuing"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class SessionsController < ApplicationController
@<%= singular_table_name %> = <%= class_name %>.find_by_email(params[:email])

if @<%= singular_table_name %>.try(:authenticate, params[:password])
render json: { session_token: @<%= singular_table_name %>.signed_session_token }
render json: { session_token: @<%= singular_table_name %>.session_token }
else
render json: { error: "Invalid email or password" }, status: :unauthorized
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class RegistrationsController < ApplicationController
@<%= singular_table_name %> = <%= class_name %>.new(<%= "#{singular_table_name}_params" %>)

if @<%= singular_table_name %>.save
cookies.signed[:session_token] = { value: @<%= singular_table_name %>.session_token, httponly: true }
cookies[:session_token] = { value: @<%= singular_table_name %>.session_token, httponly: true }
redirect_to root_path, notice: "Welcome! You have signed up successfully"
else
render :new, status: :unprocessable_entity
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ class SessionsController < ApplicationController

if @<%= singular_table_name %>.try(:authenticate, params[:password])
if params[:remember_me] == "1"
cookies.signed.permanent[:session_token] = { value: @<%= singular_table_name %>.session_token, httponly: true }
cookies.permanent[:session_token] = { value: @<%= singular_table_name %>.session_token, httponly: true }
else
cookies.signed[:session_token] = { value: @<%= singular_table_name %>.session_token, httponly: true }
cookies[:session_token] = { value: @<%= singular_table_name %>.session_token, httponly: true }
end

redirect_to root_path, notice: "Signed in successfully"
Expand Down
13 changes: 2 additions & 11 deletions lib/generators/authentication/templates/models/resource.rb.tt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ class <%= class_name %> < ApplicationRecord
has_secure_password :password
has_secure_token :session_token

encrypts :session_token, deterministic: true

validates :email, presence: true, uniqueness: true
validates :email, format: { with: /\A[^@\s]+@[^@\s]+\z/ }
validates_length_of :password, minimum: 8, allow_blank: true
Expand All @@ -21,15 +23,4 @@ class <%= class_name %> < ApplicationRecord
PasswordMailer.with(<%= singular_table_name %>: self).changed.deliver_later
end
end
<% if options.api? %>
def signed_session_token
self.class.signed_id_verifier.generate(session_token)
end

def self.find_signed_session_token(signed_session_token)
if session_token = signed_id_verifier.verified(signed_session_token)
find_by_session_token(session_token)
end
end
<% end -%>
end

0 comments on commit c942a36

Please sign in to comment.