Files

150 lines
4.6 KiB
Ruby

class Tiktok::AuthClient
REQUIRED_SCOPES = %w[user.info.basic user.info.username user.info.stats user.info.profile user.account.type user.insights message.list.read
message.list.send message.list.manage].freeze
class << self
def authorize_url(state: nil)
tiktok_client = ::OAuth2::Client.new(
client_id,
client_secret,
{
site: 'https://www.tiktok.com',
authorize_url: '/v2/auth/authorize',
auth_scheme: :basic_auth
}
)
tiktok_client.authorize_url(
{
response_type: 'code',
client_key: client_id,
redirect_uri: redirect_uri,
scope: REQUIRED_SCOPES.join(','),
state: state
}
)
end
# https://business-api.tiktok.com/portal/docs?id=1832184159540418
def obtain_short_term_access_token(auth_code) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
endpoint = "#{api_base_url}/tt_user/oauth2/token/"
headers = { 'Accept' => 'application/json', 'Content-Type' => 'application/json' }
body = {
client_id: client_id,
client_secret: client_secret,
grant_type: 'authorization_code',
auth_code: auth_code,
redirect_uri: redirect_uri
}
response = HTTParty.post(
endpoint,
body: body.to_json,
headers: headers
)
json = process_json_response(response, 'Failed to obtain TikTok short-term access token')
{
business_id: json['data']['open_id'],
scope: json['data']['scope'],
access_token: json['data']['access_token'],
refresh_token: json['data']['refresh_token'],
expires_at: Time.current + json['data']['expires_in'].seconds,
refresh_token_expires_at: Time.current + json['data']['refresh_token_expires_in'].seconds
}.with_indifferent_access
end
def renew_short_term_access_token(refresh_token) # rubocop:disable Metrics/MethodLength
endpoint = "#{api_base_url}/tt_user/oauth2/refresh_token/"
headers = { 'Accept' => 'application/json', 'Content-Type' => 'application/json' }
body = {
client_id: client_id,
client_secret: client_secret,
grant_type: 'refresh_token',
refresh_token: refresh_token
}
response = HTTParty.post(
endpoint,
body: body.to_json,
headers: headers
)
json = process_json_response(response, 'Failed to renew TikTok short-term access token')
{
access_token: json['data']['access_token'],
refresh_token: json['data']['refresh_token'],
expires_at: Time.current + json['data']['expires_in'].seconds,
refresh_token_expires_at: Time.current + json['data']['refresh_token_expires_in'].seconds
}.with_indifferent_access
end
def webhook_callback
endpoint = "#{api_base_url}/business/webhook/list/"
headers = { Accept: 'application/json' }
params = {
app_id: client_id,
secret: client_secret,
event_type: 'DIRECT_MESSAGE'
}
response = HTTParty.get(endpoint, query: params, headers: headers)
process_json_response(response, 'Failed to fetch TikTok webhook callback')
end
def update_webhook_callback
endpoint = "#{api_base_url}/business/webhook/update/"
headers = { Accept: 'application/json', 'Content-Type': 'application/json' }
body = {
app_id: client_id,
secret: client_secret,
event_type: 'DIRECT_MESSAGE',
callback_url: webhook_url
}
response = HTTParty.post(endpoint, body: body.to_json, headers: headers)
process_json_response(response, 'Failed to update TikTok webhook callback')
end
private
def client_id
GlobalConfigService.load('TIKTOK_APP_ID', nil)
end
def client_secret
GlobalConfigService.load('TIKTOK_APP_SECRET', nil)
end
def process_json_response(response, error_prefix)
unless response.success?
Rails.logger.error "#{error_prefix}. Status: #{response.code}, Body: #{response.body}"
raise "#{response.code}: #{response.body}"
end
res = JSON.parse(response.body)
raise "#{res['code']}: #{res['message']}" if res['code'] != 0
res
end
def redirect_uri
"#{base_url}/tiktok/callback"
end
def webhook_url
"#{base_url}/webhooks/tiktok"
end
def base_url
ENV.fetch('FRONTEND_URL', 'http://localhost:3000')
end
def api_base_url
"https://business-api.tiktok.com/open_api/#{GlobalConfigService.load('TIKTOK_API_VERSION', 'v1.3')}"
end
end
end