devise_token_auth
devise_token_auth copied to clipboard
CSRF protect_from_forgery with: :null_session is skipped
- Version: 1.2.0
- Environmental Info:
- Gems: devise (4.8.0), rails (6.1.4.1)
enable_standard_devise_support = trueprotect_from_forgery with: :null_session
We have controller that is already using rails session for the authentication. We want to add token auth in addition. They will run in parallel to allow transition.
Adding include DeviseTokenAuth::Concerns::SetUserByToken to the controller works well, but CSRF is broken.
After debugging it, this is why it happens:
- Request gets to the controller and we execute before actions
- We set user locale. This will get
current_user, but since it's a first time we get user, we authenticate.- When
set_user_by_tokenis called, it sets@resourceinstance variable.
- When
- CSRF before action is executed
protect_from_forgery with: :null_session- When CSRF is invalid,
handle_unverified_requestis called- https://github.com/heartcombo/devise/blob/8593801130f2df94a50863b5db535c272b00efe1/lib/devise/controllers/helpers.rb#L254-L258
- The session is reset and all good.
- Controller action is executed
- Controller requests
current_user, which isnilbecause it was cleared in the previous step set_user_by_tokenis called again to get user- Because we
enable_standard_devise_support = truewe check devise. https://github.com/lynndylanhurley/devise_token_auth/blob/6d7780ee0b9750687e7e2871b9a1c6368f2085a9/app/controllers/devise_token_auth/concerns/set_user_by_token.rb#L58 - Devise auth is
nil(correct and expected) - Then we get to this line https://github.com/lynndylanhurley/devise_token_auth/blob/6d7780ee0b9750687e7e2871b9a1c6368f2085a9/app/controllers/devise_token_auth/concerns/set_user_by_token.rb#L69
- Because
@resourcewas previously set and wasn't cleared by invalid CSRF, we authenticate user and ignore invalid CSRF token
- Controller requests
Expected: Authentication should fail after session was reset
Actual: User is authenticated with invalid CSRF token.
A temporary patch
# config/initializers/devise_token_auth.rb
# https://github.com/lynndylanhurley/devise_token_auth/issues/1514
module DeviseTokenAuthCSRFPatch
def handle_unverified_request(*)
super.tap do
@resource = nil
end
end
end
DeviseTokenAuth::Concerns::SetUserByToken.include DeviseTokenAuthCSRFPatch