Skip to content

Commit 5817f4d

Browse files
feat: add TwoFactor base Warden strategy
Provide a base strategy that handles shared 2FA boilerplate: finding the pending resource from session, calling verify_two_factor!, restoring remember_me, and cleaning up session state on success. Extensions subclass and implement valid? + verify_two_factor!. The base strategy returns valid? false to prevent accidental use.
1 parent 95b435a commit 5817f4d

1 file changed

Lines changed: 50 additions & 0 deletions

File tree

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# frozen_string_literal: true
2+
3+
require 'devise/strategies/base'
4+
5+
module Devise
6+
module Strategies
7+
class TwoFactor < Base
8+
# The base strategy is never used directly — extensions subclass it.
9+
def valid?
10+
false
11+
end
12+
13+
def authenticate!
14+
resource = find_pending_resource
15+
return fail!(:two_factor_session_expired) unless resource
16+
17+
verify_two_factor!(resource)
18+
19+
unless halted?
20+
restore_remember_me(resource)
21+
resource.after_database_authentication
22+
cleanup_two_factor_session!
23+
success!(resource)
24+
end
25+
end
26+
27+
# Extensions must override. Should call fail! with a specific
28+
# message on failure — this halts execution and triggers recall.
29+
def verify_two_factor!(resource)
30+
raise NotImplementedError
31+
end
32+
33+
private
34+
35+
def find_pending_resource
36+
return unless session[:devise_two_factor_resource_id]
37+
mapping.to.where(id: session[:devise_two_factor_resource_id]).first
38+
end
39+
40+
def restore_remember_me(resource)
41+
resource.remember_me = session[:devise_two_factor_remember_me] if resource.respond_to?(:remember_me=)
42+
end
43+
44+
def cleanup_two_factor_session!
45+
session.delete(:devise_two_factor_resource_id)
46+
session.delete(:devise_two_factor_remember_me)
47+
end
48+
end
49+
end
50+
end

0 commit comments

Comments
 (0)