Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions app/controllers/admin/sessions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,14 @@ def callback
begin
res = http.request(req)
rescue => e
Sentry.capture_exception(e)
Rails.logger.error("Admin OAuth token exchange error: #{e.class}: #{e.message}")
return redirect_to root_path, alert: 'OAuth failed'
end
return redirect_to root_path, alert: 'OAuth failed' unless res.is_a?(Net::HTTPSuccess)
unless res.is_a?(Net::HTTPSuccess)
Sentry.capture_message("OAuth token exchange failed: #{res.code} - #{res.body}")
return redirect_to root_path, alert: 'OAuth failed'
end

token_data = JSON.parse(res.body)

Expand All @@ -61,16 +65,21 @@ def callback
begin
me_res = http.request(req)
rescue => e
Sentry.capture_exception(e)
Rails.logger.error("Admin profile fetch error: #{e.class}: #{e.message}")
return redirect_to root_path, alert: 'Profile fetch failed'
end
return redirect_to root_path, alert: 'Profile fetch failed' unless me_res.is_a?(Net::HTTPSuccess)
unless me_res.is_a?(Net::HTTPSuccess)
Sentry.capture_message("Profile fetch failed: #{me_res.code} - #{me_res.body}")
return redirect_to root_path, alert: 'Profile fetch failed'
end

user_data = JSON.parse(me_res.body)['identity']
user_data = IdentityNormalizer.normalize(user_data)
# Verify and consume state
state_data = StateToken.verify(state)
if session[:admin_state_nonce].blank? || state_data.nil? || state_data['nonce'] != session[:admin_state_nonce]
Sentry.capture_message('OAuth state verification failed')
return redirect_to root_path, alert: 'OAuth failed'
end
session.delete(:admin_state_nonce)
Expand Down
5 changes: 5 additions & 0 deletions app/controllers/api/verify_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ def index
end

unless ENV['IDENTITY_URL'].present? && ENV['IDENTITY_PROGRAM_KEY'].present?
Sentry.capture_message('Missing Identity Vault configuration')
Rails.logger.error('Missing Identity Vault configuration')
attempt = create_attempt_safely!(
idv_rec: idv_rec,
Expand Down Expand Up @@ -120,6 +121,7 @@ def index
begin
res = http.request(req)
rescue => e
Sentry.capture_exception(e)
Rails.logger.error("Identity API error: #{e.class}: #{e.message}")
attempt = create_attempt_safely!(idv_rec: idv_rec, first_name: first_name, last_name: last_name, email: email, program: program_slug, submit_id: submit_id, verified: false, identity_response: nil, ip: request.remote_ip)
UserJourneyEvent.create!(event_type: 'verification_attempt', program: program_slug, idv_rec: idv_rec, email: email, request_ip: request.remote_ip, verification_attempt_id: attempt&.id, metadata: { error: 'fetch_timeout', submit_id: submit_id }) rescue nil
Expand All @@ -132,6 +134,7 @@ def index
UserJourneyEvent.create!(event_type: 'verification_attempt', program: program_slug, idv_rec: idv_rec, email: email, request_ip: request.remote_ip, verification_attempt_id: attempt&.id, metadata: { error: '404', submit_id: submit_id }) rescue nil
return render json: { verified: false, identity_response: nil }
else
Sentry.capture_message("User fetch failed: #{res.code} - #{res.body}")
Rails.logger.error("User fetch failed: #{res.code} - #{res.body}")
attempt = create_attempt_safely!(idv_rec: idv_rec, first_name: first_name, last_name: last_name, email: email, program: program_slug, submit_id: submit_id, verified: false, identity_response: nil, ip: request.remote_ip)
UserJourneyEvent.create!(event_type: 'verification_attempt', program: program_slug, idv_rec: idv_rec, email: email, request_ip: request.remote_ip, verification_attempt_id: attempt&.id, metadata: { error: 'fetch_failed', code: res.code, submit_id: submit_id }) rescue nil
Expand All @@ -144,6 +147,7 @@ def index
user_data = body['identity']
user_data = IdentityNormalizer.normalize(user_data)
rescue => e
Sentry.capture_exception(e)
Rails.logger.error("Invalid JSON from identity API: #{e.message}")
attempt = create_attempt_safely!(
idv_rec: idv_rec,
Expand Down Expand Up @@ -277,6 +281,7 @@ def index
) rescue nil
render json: { verified: false, error: 'Submit token already used', identity_response: nil }, status: :gone
rescue => e
Sentry.capture_exception(e)
Rails.logger.error("Verification error: #{e.message}")
attempt = create_attempt_safely!(idv_rec: idv_rec, first_name: first_name, last_name: last_name, email: email, program: (program_rec&.slug || program_slug), submit_id: submit_id, verified: false, identity_response: nil, ip: request.remote_ip)
UserJourneyEvent.create!(event_type: 'verification_attempt', program: (program_rec&.slug || program_slug), idv_rec: idv_rec, email: email, request_ip: request.remote_ip, verification_attempt_id: attempt&.id, metadata: { error: 'exception', message: e.message, submit_id: submit_id }) rescue nil
Expand Down
4 changes: 4 additions & 0 deletions app/controllers/identity_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def url
# Base URL for redirect_uri; prefer request.base_url if NEXTAUTH_URL missing
nextauth_url = ENV['NEXTAUTH_URL'].presence || request.base_url
unless nextauth_url.present?
Sentry.capture_message('NEXTAUTH_URL environment variable is not set')
Rails.logger.error('NEXTAUTH_URL environment variable is not set')
return render json: { error: 'Server configuration error' }, status: :internal_server_error
end
Expand Down Expand Up @@ -245,6 +246,7 @@ def callback
rescue ActiveRecord::RecordNotUnique
# If it already exists, continue (idempotent on refresh)
rescue => e
Sentry.capture_exception(e)
Rails.logger.error("Failed to issue AuthorizedSubmitToken: #{e.class}: #{e.message}")
end

Expand Down Expand Up @@ -286,6 +288,7 @@ def callback

# Centralized failure handler for OAuth flow
def oauth_fail(reason:, alert_message: 'Identity verification failed', program: nil, idv_rec: nil, email: nil, extra_metadata: {})
Sentry.capture_message("OAuth failure: #{reason} - #{alert_message}") if alert_message.to_s.downcase.include?('failed')
base_metadata = { reason: reason }.merge(extra_metadata || {})
Rails.logger.warn("OAuth failure: #{reason} metadata=#{base_metadata.inspect}")
safe_create_journey_event(
Expand All @@ -309,6 +312,7 @@ def safe_create_journey_event(event_type:, program: nil, idv_rec: nil, email: ni
metadata: metadata.presence
)
rescue => e
Sentry.capture_exception(e)
Rails.logger.error("UserJourneyEvent create failed (#{event_type}): #{e.class}: #{e.message}")
end

Expand Down
1 change: 1 addition & 0 deletions app/controllers/popup/authorize_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ def callback
render :success, layout: 'application'

rescue => e
Sentry.capture_exception(e)
Rails.logger.error("Popup OAuth error: #{e.message}")
UserJourneyEvent.create!(
event_type: 'popup_oauth_error',
Expand Down