Rails authentication from scratch
stevepolito.design
stevepolito.design
if you are worried about timing attacks then you can just have your routes in the form of `/user/<id>/reset_password/<token>` and pull the user out of the DB and then do the comparison using a timing safe function. alternatively, if that is not possible and you need to do a lookup by the token its possible to blind the value stored in the DB but i would avoid that because it introduces another cryptographic primitive unnecessarily. and having only index on user_id and not having to have indexes on all your tokens saves space as well!
The reality may be different, but superficially it seems odd.
> Rodauth is Ruby's most advanced authentication framework, designed to work in any rack application.
None of that is particularly hard, but it's a lot to build, test, and maintain. Start throwing in more account features you might take for granted elsewhere (MFA, recovery codes, re-enter current password to change your password, allow a user to sign out of all their sessions, etc etc) and you could find yourself spending all your time building your user system instead of your application features.
I would guess, for most applications, user systems are standard enough that rolling your own isn't going to be worth the possible additional customization.
Now I would typically task you with an exercise to improve your design so that the password reset mechanism, once triggered by an unauthenticated user ("reset password" is clicked) does not result in locking the legitimate account.
After a few minutes, you would likely come up with a new protocol that consists in two steps instead of one:
1. Unknown user triggers the password reset mechanism by submitting an email address to the "reset password" form.
2. Legitimate user receives a password reset link by email. If the link is clicked, the legitimate user is redirected to a prompt to provide new credentials. If the link is never clicked, nothing happens.
enjoy
Then I would challenge you again with a new threat: "Now we have a new problem. Instead of locking user accounts randomly, the attacker could just write a script that submits the password reset form repeatedly for hours, thus triggering thousands of emails and severely disrupting both our users and our email gateways."
You would say "oh! that's a great challenge!" :)
And a few minutes later, you would likely come up with the solution to implement a CAPTCHA equivalent in the first stage of the password reset mechanism to reduce the likelihood automation.
enjoy
Then I few months later, I would challenge you again with a new threat: "It appears that someone has devised a technique to bypass our CAPTCHA mechanism. We need to find something else."
You would say "oh! that's a great challenge!" :)
And a few minutes later, you would likely come up with the epiphany that no, this part of the challenge is actually not that great because we simply reached the final stage of our analysis that basically requires monitoring the world for new research work that would ultimately cancel the benefits of our CAPTCHA mechanism and force us to find something else.
But that part of the challenge is for another team ;)
Cognito + oauth2-proxy or the millions of alternatives are at your disposal.
Although for past 15 years I've socially distanced myself from Rails, I'm pretty sure it had a decent auth library at the time, something called device.
[0]: https://blog.kiprosh.com/rails-7-1-adds-authenticated_by/
Don’t write your own, but also own it, and completely abstract it. Don’t let anything but a single file in a single shared library or service know anything at all about the underlying implementation.
they basically recreated a simpler but not-as-flexible (yet?) devise. the flexibility/adaptability of devise seems to be where all the extra complexity comes from. i'm just waiting to see this released as a gem, and the cycle to start anew... =)