lazaronixon / authentication-zero Goto Github PK
View Code? Open in Web Editor NEWAn authentication system generator for Rails applications.
License: MIT License
An authentication system generator for Rails applications.
License: MIT License
Awesome work everyone, I β€οΈ this gem!
I'm curious what your thoughts on abstracting the logic that is currently housed directly into the ApplicationController
into an Authentication
concern?
This would make it easier for folks to incorporate the gem into existing projects and could even potentially allow for the DRYing up of logic between the HTML
and API
variants.
It seems to be complicated, if we could find a simple solution here... https://github.com/cedarcode/webauthn-ruby
I would like to have a repo explaining the API endpoints, like Basecamp api.
https://github.com/basecamp/bc3-api
Standardrb is really nice when it comes to a sane default code style.
For example generated controller code like:
if user && user.authenticate(params[:password])
becomes
if user&.authenticate(params[:password])
Hey mate,
nice project. Right now it skips the generation of the routes for the auth system when following the instructions from the readme.
Cheers Bijan
I'm using Rails 7.0.2.2 with Ruby 3.1.1.
Hi, I followed the instructions on the Github page to add the latest gem to my project and then ran 'rails g authentification', then migrated the database. So just a generic install without options, under Rails 7.0.3.
Tried to add myself as a new user but the registrations controller keeps rejecting the signup, with the logs reporting unpermitted parameters for :authenticity_token and :commit.
Looked at my Users model but don't see anything that jumps out. If I add those missing params to the Registrations controllers' permitted params, then the next error is "Unknown Attribute Error" for :authenticity_token on the User model.
Any idea how to fix? Thanks!
It would be very useful to allow choosing a model name other than User
. Especially when needing to create multiple types of user-like models like User
, Customer
and Admin
.
Each of email
, email_verification
and password_reset
is a singular resource in the identity
namespace; however, the password
resource is in the root namespace, despite following the pattern for the identity
controllers (i.e. the presence of Current.user
).
Would it be more consistent for password changes to sit in the identity namespace, too?
Hey, an idea...
Replace redis
to redis-client
gem which uses the new RESP3 protocol found in Redis 6.0+.
Hi,
Is it possible to consider the option that a user has more accounts associated? For example, that can log in with his Facebook, Google or Apple account. There would have to be an extra table that has provider, uid, and user_id.
What do you think? Thanks!
Every language string should be making use of Rails i18n features in order to provide a solid baseline for the addition of languages.
In another issue (#50), it was mentioned that because this gem could be removed that improvements to the codebase (eg. security updates) might be missed.
@gregmolnar made a fairly reasonable suggestion to add a post installation message to address this, presumably such that users who have used the gem should also keep the gem as part of the host application's Gemfile so that future post installation messages can be relayed to them.
@lazaronixon If this is something that you think might be helpful as well, I'd be happy to submit a PR for this. Thank you!
Implement ratelimit, I did it before....
environment nil, env: "production" do <<~CODE
config.middleware.use(
Rack::Ratelimit, name: "General",
rate: [1000, 1.hour],
logger: Rails.logger,
redis: Redis.new
) { |env| ActionDispatch::Request.new(env).ip }
CODE
Hi,
any chance you would consider adding support for inviting new users? To keep it lean and simple i think a good implementation would be to handle things like invitation tokens, expiry and the state on an invitation (pending, accepted, expired) and return an invitation link.
This would keep the gem relatively simple and leave it up to the user how to distribute the invitation link (via mail, manually, etc)
Instead put everything inside root path, create identity and sessions namespaces
It doesn't fit the authentication purpose, the user should create regular scaffolds in order to edit profile or cancel account...
users_controller, /users/id [patch] and /users/id [delete]
My main navigation bar shows either a login/sign up button or a logout/edit profile button. To get that to work, the Current.session
has to be set before. But if authenticate
is being called and the user is not logged in, it redirects to the login page - based on the current (v2.10.0).
But in that scenario you obviously don't have to be logged in to view the start page. A redirect to login is not useful in that situation.
Wouldn't it be useful to have a separate set_current_session
method in the ApplicationController
and extract setting the session from the authenticate
method?
before_action :set_current_session
before_action :authenticate
...
def authenticate
redirect_to sign_in_path unless Current.session.present?
end
def set_current_session
if session = Session.find_by_id(cookies.signed[:session_token])
Current.session = session
end
end
With that you can continue to call skip_before_action :authenticate
within all controllers that don't require an authenticated user, but the session (if available) is correctly set.
I'm fairly new to Ruby and Rails. So please excuse if I miss something here. π€
Currently all authentication action is allocated to a User model.
It may be helpful to allow this to be configurable to support alternative scenarios such as:
If the options lockable is passed, them implement locking on reset password following this wiki https://github.com/lazaronixon/authentication-zero/wiki/Password-reset-locking-redis
I would like to have a validation step for rubocop and breakman on the generated applications (GitHub actions).
Implement integration with pwned, basically just add gem 'pwned'
and validates :password, not_pwned: true
to User
Hi,
My Rails app has an api and html views. I make the difference using the json formats. Will it be possible to mix both authentication strategies somehow in the same controller? If the format is json return json, otherwise html, and always return the token, or otherwise return it only if the format is json. The other option would be to have a separate controller for api and html, but this doesn't sound so nice.
What do you think? Thanks!
I'm not sure your thoughts on this but it might be worth implementing standard or something similar for code formatting.
Happy to submit a PR if you're interested.
After running the generation with the flags --pwned --sudoable --omniauthable --two-factor
I ran into the error of missing method kredis_flag
for the session model. I had to then add the kredis
gem manually.
Running with rails 7.0.4
.
Shouldn't this gem be added to the gemfile with code generation?
Create 2 repos, api and html, after each version update these repos with the changes and tag them⦠so the user will be able to see the diffs between versions
It would be nice to store a user's destination and redirect them back to it in the event that the need to login prior to visiting the page. Similarly to how users are redirected after sudo
is required.
I was testing this gem, and when I generate a sample app with the --lockable
flag, it looks like the before_action
to call require_lock
is only added to the password reset, but it should also be added to at least to the sessions controller too I believe.
Otherwise, it gives a false sense of being safe from password brute-force attacks.
Fresh after installation I tried adding a user with the password "111111111111". Not the most secure password, but ought to work. Doesn't work, gives "password invalid" message. Took a while to figure out that the password validation contains a regex that looks like it might be limiting characters to upper and lower case letters and digits:
validates :password, allow_nil: true, length: { minimum: 6 }, format: { with: /(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])/ }
If that's the case it can be done with a much simpler regex, this one doesn't work! More to the point, why is this here at all? Isn't the restriction of characters in a password a feature that only some will want? Leave it behind a '#' if you want to let it be a reminder that such a thing can be done.
For now, each new sign in sends a new email, don't send email from the same device. hey.com seems to set a cookie called device_token, and check if this device exists
Hello,
I'm maintaining a legacy app that I'm considering moving from devise to authentication-zero. Is this possible? Any advice?
Hi,
First off, love your excellent approach and gem!
While inspecting the generated code on how the session cookie is set I can see that you are using cookies.signed.permanent . I was wondering, wouldn't it be better to leverage the default Rails session cookie; leveraging expiration, signing etc. Could be as simple as replacing
cookies.signed.permanent[:session_token] = { value: session.id, httponly: true }
with
session[:session_token] = session.id
Or is there a some reason why you decided to roll your own cookie?
I had assumed that the --api
flag was going to mean something like "in addition to the base generated auth code, also generate an API::
module and an API::BaseController
and then put the relevant controllers/routes/etc in place so that JSON requests to /api/*...
might be useful", or something along those lines.
What it seems like it actually do is more like "Generate an API-only app INSTEAD OF a regular html app" (at controller level), I think?
Thoughts on all/any of...
--api-only
for a little clarity?I'm a really bad writer, I would like to have a fancy README, maybe with a video, logo, etc... but keep it simple and direct.
Hey, it's me again ;)
The create action in registrations controller is not using an instance variable but in error case you invoke a render that then checks @user.errors.any? in the view. So an exception is thrown (see screenshot).
It's a simple fix and pull request is on the way :)
Cheers Bijan
PS: We should maybe create a test suite for this gem that does the generate a new application and runs default tests on it so we can see when some generator changes lead to a break of the gem. What do you think?
I ran the generator in an app I had already been working on and saw that several files were overwritten, and one generated file omitted.
Files n classes overwritten, losing my existing app behavior:
Files skipped that other auth zero behavior depended on:
Files modified in place, the behavior I would expect:
In your README.md in the Usage section, right after "Then run bundle install again!" - you should include a call to 'rake db:migrate'
thanks
Implement activity log, A history of security-related activity on your account. Logging in or out, changing your password, etc.
In order to create a solid solution usable by many apps it would make sense to put regression testing in place.
Generators themselves are not easy to test but the workaround would be to create a build pipeline that runs a script that creates a new blank rails app, adds the gem, adds the controller, modifies the routes and adds the mail settings etc.
When the new barebone app is finished and authentication-zero is setup it runs a test suite on the generated app.
Not sure how to put the test suite in place (cloning from repo?, generating?).
What do you think @lazaronixon?
It would be nice if I could have the option to create a email magic link authentication method. π
Integrate with https://github.com/omniauth/omniauth or https://github.com/basecamp/google_sign_in, the simplest solution
It appears that the system tests can become flakey where the test visits a url, and straight after fills in a form field.
This can, under certain circumstances, cause a timing issue where the field does not get filled in. I noticed that the page was still stuck on the page with a tip expecting the field to be filled in. I solved this for my usage by simply asserting something specific to the page that is to be loaded.
The flakiness was also very noticeable with one of the system tests failing every 3rd/4th run.
For example:
test "sending a password reset email" do
visit sign_in_url
click_on "Forgot your password?"
assert_css "h1", text: "Forgot your password?" # I added this to ensure the test is on the right page
fill_in "Email", with: @user.email
click_on "Send password reset email"
assert_text "Check your email for reset instructions"
end
Example random failure with screenshot:
Failure:
Identity::PasswordResetsTest#test_sending_a_password_reset_email [***omitted***/test/system/identity/password_resets_test.rb:19]:
expected to find text "Check your email for reset instructions" in "Forgot your password?\nEmail"
This would avoid having to create models to store the password reset and email confirmation tokens.
More information here.
After code generation, running version 2.1.16
, rails complains about the has_many :sessions
relationship with:
Rails couldn't find a valid model for session association.
Please provide the :class_name option on the association declaration.
If :class_name is already provided, make sure it's an ActiveRecord::Base subclass. (NameError)
Making the change in user.rb
solved it for me.
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -6,7 +6,7 @@ class User < ApplicationRecord
has_many :email_verification_tokens, dependent: :destroy
has_many :password_reset_tokens, dependent: :destroy
- has_many :sessions, dependent: :destroy
+ has_many :sessions, dependent: :destroy, class_name: "Session"
The question is, why is this needed? Whats changed?
Running on Rails 7.0.4
I ran the generator after I had already created, and added behavior to, file app/models/current.rb
and auth-zero content was not added. I think it ought to have added the new behavior to the existing file if it were present.
Rails 7.1 brings a new authentication mechanism that helps mitigate timing-based enumeration attacks.
See egde-docs here:
This issue could be kept as a reminder to switch behaviour as soon as it's released.
This would simplify the logic for changing the password in the passwords controller.
More information here.
If the option 2fa is passed implement two factor authentication using rotp, simplest possible, the code must be still less than 200 lines of code
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.