You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
docuseal/app/controllers/concerns/clerk_devise_bridge.rb

59 lines
1.9 KiB

# frozen_string_literal: true
# Bridges Clerk's apex-cookie SSO into Devise. When a request arrives with a
# valid Clerk session JWT belonging to the Bloombilt Staff org, find or
# auto-provision the matching Devise User and call sign_in so the rest of the
# app (which authorizes via Devise + CanCanCan) sees the request as
# authenticated. Devise's password login at /users/sign_in is preserved as
# emergency access.
module ClerkDeviseBridge
extend ActiveSupport::Concern
STAFF_ORG_SLUG = 'bloombilt-staff'
included do
before_action :sign_in_from_clerk_session, unless: :devise_controller?
end
private
def sign_in_from_clerk_session
return if user_signed_in?
clerk_user = safe_clerk_user
return unless clerk_user
return unless clerk.organization&.slug == STAFF_ORG_SLUG
email = primary_email(clerk_user)
return unless email
user = User.active.find_by(email: email) || provision_user_for_clerk(email, clerk_user)
return unless user
sign_in(user, store: true)
end
def safe_clerk_user
clerk.user
rescue StandardError => e
Rails.logger.warn("[clerk-bridge] reading clerk.user failed: #{e.class}: #{e.message}")
nil
end
def primary_email(clerk_user)
addresses = clerk_user.respond_to?(:email_addresses) ? clerk_user.email_addresses : nil
addresses&.first&.email_address&.to_s&.downcase.presence
end
def provision_user_for_clerk(email, clerk_user)
first_name = clerk_user.respond_to?(:first_name) ? clerk_user.first_name : nil
last_name = clerk_user.respond_to?(:last_name) ? clerk_user.last_name : nil
User.provision_clerk_admin(email: email, first_name: first_name, last_name: last_name)
rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotUnique => e
Rails.logger.warn("[clerk-bridge] provision failed for #{email}: #{e.message}")
User.active.find_by(email: email)
end
end