feat: Add WhatsApp reauthorization bankend flow

This commit is contained in:
Tanmay Deep Sharma
2025-07-10 03:09:16 +07:00
parent 358ec8120b
commit 9007bf1ecf
5 changed files with 195 additions and 1 deletions
@@ -32,6 +32,28 @@ class Whatsapp::EmbeddedController < ApplicationController
handle_signup_error(e)
end
def reauthorize
# Reauthorize existing WhatsApp inbox using embedded signup flow
validate_authorization_code!
return if performed?
validate_required_parameters!
return if performed?
validate_inbox_id!
return if performed?
channel = process_reauthorization
@inbox = channel.inbox
# Clear reauthorization required flag
channel.reauthorized!
render json: { message: 'WhatsApp channel reauthorized successfully' }, status: :ok
rescue StandardError => e
handle_signup_error(e)
end
private
def validate_authorization_code!
@@ -51,6 +73,14 @@ class Whatsapp::EmbeddedController < ApplicationController
}, status: :bad_request
end
def validate_inbox_id!
return if params[:inbox_id].present?
render json: {
error: 'Missing inbox_id parameter'
}, status: :bad_request
end
def process_signup
service = Whatsapp::EmbeddedSignupService.new(
account: Current.account,
@@ -63,6 +93,19 @@ class Whatsapp::EmbeddedController < ApplicationController
service.perform
end
def process_reauthorization
service = Whatsapp::EmbeddedSignupService.new(
account: Current.account,
code: params[:code],
business_id: params[:business_id],
waba_id: params[:waba_id],
phone_number_id: params[:phone_number_id],
inbox_id: params[:inbox_id]
)
service.perform_reauthorization
end
def handle_signup_error(error)
Rails.logger.error("WhatsApp embedded signup processing error: #{error.message}")
Rails.logger.error(error.backtrace.join("\n"))
@@ -1,12 +1,13 @@
class Whatsapp::EmbeddedSignupService
include Rails.application.routes.url_helpers
def initialize(account:, code:, business_id:, waba_id:, phone_number_id:)
def initialize(account:, code:, business_id:, waba_id:, phone_number_id:, inbox_id: nil)
@account = account
@code = code
@business_id = business_id
@waba_id = waba_id
@phone_number_id = phone_number_id
@inbox_id = inbox_id
end
def perform
@@ -33,6 +34,43 @@ class Whatsapp::EmbeddedSignupService
raise e
end
def perform_reauthorization
# Validate required parameters
unless @code.present? && @business_id.present? && @waba_id.present? && @phone_number_id.present? && @inbox_id.present?
raise ArgumentError, 'Code, business_id, waba_id, phone_number_id, and inbox_id are all required for reauthorization'
end
# Find the existing inbox and channel
inbox = @account.inboxes.find_by(id: @inbox_id)
raise ActiveRecord::RecordNotFound, 'Inbox not found' unless inbox
raise ArgumentError, 'Inbox is not a WhatsApp channel' unless inbox.channel_type == 'Channel::Whatsapp'
channel = inbox.channel
raise ArgumentError, 'Channel is not WhatsApp Cloud provider' unless channel.provider == 'whatsapp_cloud'
GlobalConfig.clear_cache
# Exchange code for new access token
access_token = exchange_code_for_token
# Use the provided business info directly
phone_info = fetch_phone_info_via_waba(@waba_id, @phone_number_id, access_token)
# Validate that the token has access to the provided WABA
validate_token_waba_access(access_token, @waba_id)
# Update the channel with new access token and configuration
update_channel_for_reauthorization(channel, phone_info, access_token)
# Re-register webhook with new token
register_phone_number(phone_info[:phone_number_id], access_token)
override_waba_webhook(@waba_id, channel, access_token)
channel
rescue StandardError => e
Rails.logger.error("[WHATSAPP] Reauthorization failed: #{e.message}")
raise e
end
private
def whatsapp_api_version
@@ -138,6 +176,18 @@ class Whatsapp::EmbeddedSignupService
)
end
def update_channel_for_reauthorization(channel, phone_info, access_token)
# Update channel with new access token and configuration
channel.update!(
provider_config: channel.provider_config.merge(
'api_key' => access_token,
'phone_number_id' => phone_info[:phone_number_id],
'business_account_id' => @waba_id,
'reauthorized_at' => Time.current.iso8601
)
)
end
def sanitize_phone_number(phone_number)
return phone_number if phone_number.blank?
@@ -116,4 +116,5 @@ json.provider resource.channel.try(:provider)
if resource.whatsapp?
json.message_templates resource.channel.try(:message_templates)
json.provider_config resource.channel.try(:provider_config) if Current.account_user&.administrator?
json.reauthorization_required resource.channel.try(:reauthorization_required?)
end
+1
View File
@@ -486,6 +486,7 @@ Rails.application.routes.draw do
get 'signup', to: 'embedded#new'
get 'signup/callback', to: 'embedded#callback'
post 'embedded_signup', to: 'embedded#embedded_signup'
post 'reauthorize', to: 'embedded#reauthorize'
end
namespace :twitter do
+99
View File
@@ -0,0 +1,99 @@
#!/usr/bin/env ruby
# Script to get business account path for a specific inbox ID
# Usage: ruby get_business_account_path.rb
# Set the inbox ID to query
INBOX_ID = 1090
# Load Rails environment (assuming this script is run from the Rails app root)
require_relative 'config/environment'
def get_business_account_path(inbox_id)
# Find the inbox by ID
inbox = Inbox.find(inbox_id)
# Check if this is a WhatsApp inbox
unless inbox.whatsapp?
puts "Error: Inbox #{inbox_id} is not a WhatsApp inbox. Channel type: #{inbox.channel_type}"
return nil
end
# Get the WhatsApp channel
whatsapp_channel = inbox.channel
# Check if it's a WhatsApp Cloud provider
unless whatsapp_channel.provider == 'whatsapp_cloud'
puts "Error: Inbox #{inbox_id} is not using WhatsApp Cloud provider. Provider: #{whatsapp_channel.provider}"
return nil
end
# Get the business_account_id and api_key from provider_config
business_account_id = whatsapp_channel.provider_config['business_account_id']
api_key = whatsapp_channel.provider_config['api_key']
if business_account_id.blank?
puts "Error: No business_account_id found in provider_config for inbox #{inbox_id}"
return nil
end
if api_key.blank?
puts "Error: No api_key (access token) found in provider_config for inbox #{inbox_id}"
return nil
end
# Construct the business account path (following the pattern from WhatsappCloudService)
api_base_path = ENV.fetch('WHATSAPP_CLOUD_BASE_URL', 'https://graph.facebook.com')
business_account_path = "#{api_base_path}/v14.0/#{business_account_id}"
return {
inbox_id: inbox_id,
inbox_name: inbox.name,
business_account_id: business_account_id,
business_account_path: business_account_path,
provider: whatsapp_channel.provider,
phone_number: whatsapp_channel.phone_number,
api_key: api_key,
access_token: api_key # alias for clarity
}
rescue ActiveRecord::RecordNotFound
puts "Error: Inbox with ID #{inbox_id} not found"
return nil
rescue StandardError => e
puts "Error: #{e.message}"
puts e.backtrace.first(5).join("\n") if ENV['DEBUG']
return nil
end
# Main execution
puts "Getting business account path for inbox ID: #{INBOX_ID}"
puts '=' * 50
result = get_business_account_path(INBOX_ID)
if result
puts 'Success! Found WhatsApp Business Account details:'
puts
puts "Inbox ID: #{result[:inbox_id]}"
puts "Inbox Name: #{result[:inbox_name]}"
puts "Phone Number: #{result[:phone_number]}"
puts "Provider: #{result[:provider]}"
puts "Business Account ID: #{result[:business_account_id]}"
puts
puts 'Business Account Path:'
puts result[:business_account_path]
puts
puts 'Access Token (API Key):'
puts result[:access_token]
puts
puts 'Complete API Endpoint Examples:'
puts "• Message Templates: #{result[:business_account_path]}/message_templates?access_token=#{result[:access_token]}"
puts "• Phone Numbers: #{result[:business_account_path]}/phone_numbers?access_token=#{result[:access_token]}"
puts
puts 'Authorization Header Format:'
puts "Authorization: Bearer #{result[:access_token]}"
else
puts "Failed to get business account path for inbox ID #{INBOX_ID}"
exit 1
end