Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Save session.id in session #53

Closed
wants to merge 5 commits into from

Conversation

JoeSouthan
Copy link
Contributor

Fixes #44

I've refactored the sign/in out flow to use the session rather than a cookie.

Couple of things of note:

  • This introduces an n+1 query, loading the Passwordless::Session, then the authenticatable
    • Could possibly store the Authenticatable in the session as well, but that adds complexity
    • Could employ some Rails caching to prevent loading the Session each time
  • This is a breaking change in that ControllerHelpers.passwordless_for is now required to set up controllers with the correct resource to authenticate against, however I've made some of the other method params optional. Wondering if it's better to just remove the superfluous params?
  • Instead of deprecating ControllerHelpers#authenticate_by_cookie, what do you think of removing it since it's a breaking change?

Let me know what you think!

@mikker
Copy link
Owner

mikker commented May 8, 2019

Nice!

  • I don't think it's a problem to fetch both Session and Authenticatable. The user can lazy load the Authenticatable and, say, only look for session in their require_user! method, then only fetch the associated record if current_user is called. I don't think we should add the caching as it'll only add more complexity for a tiny gain.
  • I don't really like the new passwordless_for in ApplicationController. Could we get the information we need from whatever the user has already put in their routes? I feel like if we have to change the apis it should be towards less magic and more normal Ruby/Rails code.
  • What are the benefits of using session over cookie? Can we get the same, long expiry? Then I'm okay with switching. And if we do, you're right that authenticate_by_cookie isn't the best name 😁

Thank you for doing this!

@JoeSouthan
Copy link
Contributor Author

Thanks for taking a look at the PR!

I've

  • Refactored it to touch less of the existing API.
  • Kept authenticate_by_session but removed the controller setup - I agree it was a bit too magic 🎉

As it stood, cookies did expose implementation details (model type) and allowed for session fixation. I've added reset_session as suggested by the Rails docs to help mitigate this.

As to expiry, it will now honour whatever is in Rails.application.config.session_store.expires_at or Session#expired?.

Copy link
Owner

@mikker mikker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice updates! Left a few comments. I like how you've handled the deprecations and api changes!

end

def cookie_key(authenticatable_class)
DeprecatedSecretsController.new.send(:cookie_key, authenticatable_class)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's pull this method out into its own file so we can test it on its own and we don't need weird (in a Rails context) initialisation?

@@ -12,6 +12,10 @@ def create_session_for(user)
)
end

def session_key(authenticatable_class)
Passwordless::SessionsController.new.send(:session_key, authenticatable_class)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

touch(:claimed_at)
end

def claimed?
!!claimed_at
end

def valid_session?
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

session.valid_session? has a double session. Let's rename to session.valid? ?

# Returns the {Passwordless::Session} (if set) from the session.
# @return [Session, nil]
def current_passwordless_session(authenticatable_class)
@current_passwordless_session ||= Passwordless::Session.find_by(id: session[session_key(authenticatable_class)])
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really like to memoize on behalf of the user. My guess is it is only going to lead to weird, hard to figure out inconsistencies? Rose memoization is widely enough known that we can assume people know to do it if they want it.

The readme already suggests to memoize current_user which is, probably, mostly what these methods will be used for.

# @see ModelHelpers#passwordless_with
def authenticate_by_session(authenticatable_class)
return unless current_passwordless_session(authenticatable_class)&.valid_session?
@current_authenticatable ||= current_passwordless_session(authenticatable_class).authenticatable
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same concern about memoization as above.

build_passwordless_session(record).tap { |s| s.save! }
end

sign_out(authenticatable_class)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this to make sure to clear the old cookies?

key = cookie_name(authenticatable_class)
cookies.encrypted.permanent[key] = {value: nil}
cookies.delete(key)
# /deprecated

reset_session
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice find in the docs 👏

@mikker
Copy link
Owner

mikker commented May 27, 2019

Thanks a bunch for yet another great addition 💙💚💛💜❤️ !

@mikker
Copy link
Owner

mikker commented Aug 29, 2019

@JoeSouthan I'm not seeing session persistence in my app using this. Sessions behave like session and reset between browser sessions, no matter what I set as Rails.application.config.session_store.expires_after.

@mikker
Copy link
Owner

mikker commented Aug 30, 2019

Actually, I think that might've been due to this and not a session vs cookies thing: #61

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Save session.id in cookie instead of user.id to allow expiration
2 participants