tiktok-open-sdk 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/.yardopts +12 -0
- data/CHANGELOG.md +15 -0
- data/README.md +215 -2
- data/lib/tiktok/open/omniauth/strategies/tiktok_open_sdk.rb +177 -0
- data/lib/tiktok/open/sdk/config.rb +42 -15
- data/lib/tiktok/open/sdk/helpers/auth_helper.rb +56 -0
- data/lib/tiktok/open/sdk/helpers/response_helper.rb +29 -0
- data/lib/tiktok/open/sdk/helpers/string_utils_helper.rb +24 -0
- data/lib/tiktok/open/sdk/helpers/validators/token_validator.rb +38 -0
- data/lib/tiktok/open/sdk/http_client.rb +11 -3
- data/lib/tiktok/open/sdk/open_api/auth/client.rb +2 -3
- data/lib/tiktok/open/sdk/open_api/auth/user.rb +3 -2
- data/lib/tiktok/open/sdk/open_api/post/publish.rb +39 -0
- data/lib/tiktok/open/sdk/open_api/user.rb +74 -0
- data/lib/tiktok/open/sdk/version.rb +1 -1
- data/lib/tiktok/open/sdk.rb +49 -3
- metadata +11 -4
- data/lib/tiktok/open/sdk/open_api/auth/helpers.rb +0 -73
- data/lib/tiktok/open/sdk/string_utils.rb +0 -24
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 804836be4e23b6a46c29c263b7b6d802cd2e6a70c61ed02a8f70328715649236
|
|
4
|
+
data.tar.gz: d2dee367fb303f07078a5e07a5a303f163db4895bb3e7468bbdeb2678308e1db
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 860dfd7da6a964785d661f1e6c9b2fd84bb324f1c8511207c0b3f981239b5d361490b8c410f31d0600bd5b4302c21b3b0cc69e370ad80814c1dc24c05b03ab06
|
|
7
|
+
data.tar.gz: 7707f1602f9c088c7d84aff5c20101138fd30e9bfb91569f13062c7e56591361fe4b1ecff06ee6b26b82ee89f362ffb2b5244fb4823c7989b8d9c125df9f9bd2
|
data/.rubocop.yml
CHANGED
data/.yardopts
ADDED
data/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.4.0] - 2025-10-06
|
|
10
|
+
### Added
|
|
11
|
+
- **OmniAuth Strategy** - Ready-to-use OmniAuth strategy for TikTok Open Platform integration in Rails applications
|
|
12
|
+
- Supports multiple TikTok OAuth scopes (user.info.basic, user.info.profile, user.info.stats)
|
|
13
|
+
- Automatic token handling and user info retrieval
|
|
14
|
+
- Rails/Devise integration examples and callbacks
|
|
15
|
+
- **Post API** - New module for interacting with TikTok's Post API endpoints
|
|
16
|
+
- Creator info query functionality for video publishing workflows
|
|
17
|
+
- Support for querying creator settings and capabilities
|
|
18
|
+
|
|
19
|
+
## [0.3.0] - 2025-09-20
|
|
20
|
+
### Added
|
|
21
|
+
- User information retrieval from TikTok API
|
|
22
|
+
- Improved request validation and error handling
|
|
23
|
+
|
|
9
24
|
## [0.2.0] - 2025-09-17
|
|
10
25
|
### Added
|
|
11
26
|
- Support for obtaining a client access token directly from the TikTok Open API, enabling secure server-to-server authentication for backend integrations and service authentication flows.
|
data/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# TikTok Open SDK
|
|
2
2
|
|
|
3
|
-
[](https://rubygems.org/gems/tiktok-open-sdk)
|
|
4
4
|
[](https://www.ruby-lang.org/en/downloads/)
|
|
5
5
|
[](LICENSE.txt)
|
|
6
6
|
[](https://github.com/pochkuntaras/tiktok-open-sdk/actions/workflows/main.yml)
|
|
@@ -10,8 +10,11 @@ A comprehensive Ruby SDK for integrating with TikTok Open API. This gem provides
|
|
|
10
10
|
## Features
|
|
11
11
|
|
|
12
12
|
- **OAuth 2.0 Authentication** – Seamless OAuth flow for secure integration
|
|
13
|
+
- **OmniAuth Strategy** – Ready-to-use OmniAuth strategy for Rails applications
|
|
13
14
|
- **Client Authentication** – Server-to-server authentication with client credentials
|
|
14
15
|
- **Token Management** – Easy access token exchange and refresh
|
|
16
|
+
- **User API** – Convenient methods to access user information
|
|
17
|
+
- **Post API** – Methods for querying creator information and video publishing
|
|
15
18
|
- **HTTP Client** – Built-in client for interacting with TikTok APIs
|
|
16
19
|
|
|
17
20
|
## Installation
|
|
@@ -54,6 +57,11 @@ Tiktok::Open::Sdk.configure do |config|
|
|
|
54
57
|
config.user_auth.auth_url = 'https://www.tiktok.com/v2/auth/authorize/'
|
|
55
58
|
config.user_auth.token_url = 'https://open.tiktokapis.com/v2/oauth/token/'
|
|
56
59
|
config.user_auth.revoke_token_url = 'https://open.tiktokapis.com/v2/oauth/revoke/'
|
|
60
|
+
config.user_info_url = 'https://open.tiktokapis.com/v2/user/info/'
|
|
61
|
+
config.creator_info_query_url = 'https://open.tiktokapis.com/v2/post/publish/creator_info/query/'
|
|
62
|
+
|
|
63
|
+
# Optional: Enable OmniAuth strategy auto-loading
|
|
64
|
+
config.load_omniauth = true
|
|
57
65
|
end
|
|
58
66
|
```
|
|
59
67
|
|
|
@@ -156,12 +164,132 @@ end
|
|
|
156
164
|
|
|
157
165
|
**Note:** Client tokens are used for server-to-server authentication and have different scopes and permissions than user tokens.
|
|
158
166
|
|
|
167
|
+
### Using the Post API
|
|
168
|
+
|
|
169
|
+
The SDK provides convenient methods for interacting with TikTok's Post API:
|
|
170
|
+
|
|
171
|
+
#### Creator Info Query
|
|
172
|
+
|
|
173
|
+
Query creator information for video publishing:
|
|
174
|
+
|
|
175
|
+
```ruby
|
|
176
|
+
# Get creator information
|
|
177
|
+
response = Tiktok::Open::Sdk.post.creator_info_query(access_token: access_token)
|
|
178
|
+
|
|
179
|
+
if response[:success]
|
|
180
|
+
creator_data = response[:response][:data]
|
|
181
|
+
|
|
182
|
+
puts "Creator Avatar: #{creator_data[:creator_avatar_url]}"
|
|
183
|
+
puts "Creator Nickname: #{creator_data[:creator_nickname]}"
|
|
184
|
+
puts "Max Video Duration: #{creator_data[:max_video_post_duration_sec]} seconds"
|
|
185
|
+
puts "Privacy Options: #{creator_data[:privacy_level_options]}"
|
|
186
|
+
else
|
|
187
|
+
puts "Error: #{response[:response][:error][:message]}"
|
|
188
|
+
end
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Using the User API
|
|
192
|
+
|
|
193
|
+
The SDK provides a convenient way to access user information:
|
|
194
|
+
|
|
195
|
+
```ruby
|
|
196
|
+
# Get user information
|
|
197
|
+
response = Tiktok::Open::Sdk.user.get_user_info(
|
|
198
|
+
access_token: access_token,
|
|
199
|
+
fields: %w[open_id union_id avatar_url display_name]
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
if response[:success]
|
|
203
|
+
user_data = response[:response][:data][:user]
|
|
204
|
+
|
|
205
|
+
puts "User ID: #{user_data[:open_id]}"
|
|
206
|
+
puts "Display Name: #{user_data[:display_name]}"
|
|
207
|
+
else
|
|
208
|
+
puts "Error: #{response[:response][:error][:message]}"
|
|
209
|
+
end
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Available user fields include:
|
|
213
|
+
- `open_id` - User's Open ID
|
|
214
|
+
- `union_id` - User's Union ID
|
|
215
|
+
- `avatar_url` - User's avatar URL
|
|
216
|
+
- `display_name` - User's display name
|
|
217
|
+
- `username` - User's username
|
|
218
|
+
- And more (see documentation for full list)
|
|
219
|
+
|
|
220
|
+
### Using OmniAuth Strategy
|
|
221
|
+
|
|
222
|
+
The SDK provides a ready-to-use OmniAuth strategy for Rails applications:
|
|
223
|
+
|
|
224
|
+
#### Rails Setup
|
|
225
|
+
|
|
226
|
+
Add the OmniAuth strategy to your Rails application:
|
|
227
|
+
|
|
228
|
+
```ruby
|
|
229
|
+
# config/initializers/devise.rb
|
|
230
|
+
Devise.setup do |config|
|
|
231
|
+
config.omniauth(
|
|
232
|
+
:tiktok_open_sdk,
|
|
233
|
+
Rails.application.credentials.dig(:tiktok, :client_key),
|
|
234
|
+
Rails.application.credentials.dig(:tiktok, :client_secret),
|
|
235
|
+
scope: 'user.info.basic,user.info.profile,user.info.stats',
|
|
236
|
+
)
|
|
237
|
+
end
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Or use the SDK configuration:
|
|
241
|
+
|
|
242
|
+
```ruby
|
|
243
|
+
# config/initializers/tiktok_sdk.rb
|
|
244
|
+
Tiktok::Open::Sdk.configure do |config|
|
|
245
|
+
config.client_key = Rails.application.credentials.dig(:tiktok, :client_key)
|
|
246
|
+
config.client_secret = Rails.application.credentials.dig(:tiktok, :client_secret)
|
|
247
|
+
config.user_auth.scopes = %w[user.info.basic video.publish]
|
|
248
|
+
config.user_auth.redirect_uri = "#{Rails.application.config.action_mailer.asset_host.chomp('/')}/users/auth/tiktok_open_sdk/callback"
|
|
249
|
+
config.load_omniauth = true
|
|
250
|
+
end
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
#### OmniAuth Callback
|
|
254
|
+
|
|
255
|
+
Handle the OmniAuth callback in your controller:
|
|
256
|
+
|
|
257
|
+
```ruby
|
|
258
|
+
# app/controllers/omniauth_callbacks_controller.rb
|
|
259
|
+
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
|
260
|
+
def tiktok_open_sdk
|
|
261
|
+
@auth = request.env['omniauth.auth']
|
|
262
|
+
|
|
263
|
+
# Find or create user based on TikTok auth data
|
|
264
|
+
@user = User.find_for_oauth(@auth)
|
|
265
|
+
|
|
266
|
+
# ...
|
|
267
|
+
|
|
268
|
+
if @user.persisted?
|
|
269
|
+
sign_in_and_redirect @user, event: :authentication
|
|
270
|
+
set_flash_message :notice, :success, kind: 'TikTok'
|
|
271
|
+
else
|
|
272
|
+
session['devise.provider_data'] = @auth.except('extra')
|
|
273
|
+
redirect_to new_user_registration_url
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
#### Supported Scopes
|
|
280
|
+
|
|
281
|
+
The OmniAuth strategy supports the following TikTok scopes:
|
|
282
|
+
|
|
283
|
+
- `user.info.basic` - Basic user info: open_id, union_id, display_name, avatar URLs
|
|
284
|
+
- `user.info.profile` - Profile info: username, bio_description, profile_deep_link, is_verified
|
|
285
|
+
- `user.info.stats` - Statistics: follower_count, following_count, likes_count, video_count
|
|
286
|
+
|
|
159
287
|
### Using the HTTP Client
|
|
160
288
|
|
|
161
289
|
The SDK includes a flexible HTTP client for making API calls:
|
|
162
290
|
|
|
163
291
|
```ruby
|
|
164
|
-
# GET request
|
|
292
|
+
# GET request using request method
|
|
165
293
|
response = Tiktok::Open::Sdk::HttpClient.request(
|
|
166
294
|
:get,
|
|
167
295
|
'https://open.tiktokapis.com/v2/user/info/',
|
|
@@ -173,6 +301,17 @@ response = Tiktok::Open::Sdk::HttpClient.request(
|
|
|
173
301
|
}
|
|
174
302
|
)
|
|
175
303
|
|
|
304
|
+
# GET request using get method
|
|
305
|
+
response = Tiktok::Open::Sdk::HttpClient.get(
|
|
306
|
+
'https://open.tiktokapis.com/v2/user/info/',
|
|
307
|
+
params: {
|
|
308
|
+
fields: 'open_id,union_id,avatar_url'
|
|
309
|
+
},
|
|
310
|
+
headers: {
|
|
311
|
+
'Authorization' => "Bearer #{access_token}"
|
|
312
|
+
}
|
|
313
|
+
)
|
|
314
|
+
|
|
176
315
|
# POST request
|
|
177
316
|
response = Tiktok::Open::Sdk::HttpClient.post(
|
|
178
317
|
'https://open.tiktokapis.com/v2/video/list/',
|
|
@@ -241,6 +380,18 @@ class TiktokAuthController < ApplicationController
|
|
|
241
380
|
session[:tiktok_access_token] = token_data[:access_token]
|
|
242
381
|
session[:tiktok_refresh_token] = token_data[:refresh_token]
|
|
243
382
|
|
|
383
|
+
# Fetch user information
|
|
384
|
+
user_response = Tiktok::Open::Sdk::OpenApi::User.get_user_info(
|
|
385
|
+
access_token: token_data[:access_token],
|
|
386
|
+
fields: %w[open_id display_name avatar_url]
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
if user_response[:success]
|
|
390
|
+
user_data = user_response[:response][:data][:user]
|
|
391
|
+
session[:tiktok_user_name] = user_data[:display_name]
|
|
392
|
+
session[:tiktok_avatar] = user_data[:avatar_url]
|
|
393
|
+
end
|
|
394
|
+
|
|
244
395
|
redirect_to dashboard_path, notice: 'Successfully connected to TikTok!'
|
|
245
396
|
else
|
|
246
397
|
redirect_to root_path, alert: 'Failed to authenticate with TikTok'
|
|
@@ -276,6 +427,7 @@ Tiktok::Open::Sdk.configure do |config|
|
|
|
276
427
|
config.client_secret = 'your_client_secret' # Required
|
|
277
428
|
config.user_auth.scopes = %w[user.info.basic] # Optional
|
|
278
429
|
config.user_auth.redirect_uri = 'https://...' # Optional
|
|
430
|
+
config.user_info_url = 'https://open.tiktokapis.com/v2/user/info/' # Optional
|
|
279
431
|
end
|
|
280
432
|
```
|
|
281
433
|
|
|
@@ -341,6 +493,56 @@ Obtains a client access token for server-to-server authentication.
|
|
|
341
493
|
}
|
|
342
494
|
```
|
|
343
495
|
|
|
496
|
+
### User API
|
|
497
|
+
|
|
498
|
+
#### `get_user_info(access_token:, fields:, validate: true)`
|
|
499
|
+
|
|
500
|
+
Retrieves user information from the TikTok Open API.
|
|
501
|
+
|
|
502
|
+
**Parameters:**
|
|
503
|
+
- `access_token` (String, required) - OAuth2 access token for authentication
|
|
504
|
+
- `fields` (Array<String>, required) - User fields to retrieve (must be valid fields)
|
|
505
|
+
- `validate` (Boolean, optional) - Whether to validate the token and fields (default: true)
|
|
506
|
+
|
|
507
|
+
**Returns:** Hash with `:success`, `:code`, and `:response` keys
|
|
508
|
+
|
|
509
|
+
**Available Fields:**
|
|
510
|
+
- `open_id` - Unique identifier for the user within the current application
|
|
511
|
+
- `union_id` - Persistent identifier for the user across different applications from the same developer
|
|
512
|
+
- `avatar_url` - URL to the user's profile image
|
|
513
|
+
- `avatar_url_100` - URL to the user's profile image in 100x100 pixel size
|
|
514
|
+
- `avatar_large_url` - URL to the user's profile image in higher resolution
|
|
515
|
+
- `display_name` - User's display name shown on their TikTok profile
|
|
516
|
+
- `bio_description` - User's biography text (if available)
|
|
517
|
+
- `profile_deep_link` - Direct link to the user's TikTok profile page
|
|
518
|
+
- `is_verified` - Boolean indicating if the account is verified by TikTok
|
|
519
|
+
- `username` - User's unique TikTok username
|
|
520
|
+
- `follower_count` - Number of followers the user has
|
|
521
|
+
- `following_count` - Number of accounts the user is following
|
|
522
|
+
- `likes_count` - Total number of likes received across all user's videos
|
|
523
|
+
- `video_count` - Total number of publicly posted videos by the user
|
|
524
|
+
|
|
525
|
+
### Post API
|
|
526
|
+
|
|
527
|
+
#### `creator_info_query(access_token:)`
|
|
528
|
+
|
|
529
|
+
Queries creator information from the TikTok Open API for video publishing.
|
|
530
|
+
|
|
531
|
+
**Parameters:**
|
|
532
|
+
- `access_token` (String, required) - OAuth2 access token for authentication
|
|
533
|
+
|
|
534
|
+
**Returns:** Hash with `:success`, `:code`, and `:response` keys
|
|
535
|
+
|
|
536
|
+
**Response Data:**
|
|
537
|
+
- `creator_avatar_url` - Creator's avatar URL
|
|
538
|
+
- `creator_nickname` - Creator's display name
|
|
539
|
+
- `creator_username` - Creator's username
|
|
540
|
+
- `stitch_disabled` - Whether stitch is disabled for the creator
|
|
541
|
+
- `comment_disabled` - Whether comments are disabled for the creator
|
|
542
|
+
- `duet_disabled` - Whether duet is disabled for the creator
|
|
543
|
+
- `max_video_post_duration_sec` - Maximum video duration in seconds
|
|
544
|
+
- `privacy_level_options` - Available privacy level options
|
|
545
|
+
|
|
344
546
|
### HTTP Client
|
|
345
547
|
|
|
346
548
|
#### `request(method, url, params: {}, headers: {}, body: nil)`
|
|
@@ -356,6 +558,17 @@ Performs HTTP requests.
|
|
|
356
558
|
|
|
357
559
|
**Returns:** `Net::HTTPResponse` object
|
|
358
560
|
|
|
561
|
+
#### `get(url, params: {}, headers: {})`
|
|
562
|
+
|
|
563
|
+
Convenience method for GET requests.
|
|
564
|
+
|
|
565
|
+
**Parameters:**
|
|
566
|
+
- `url` (String) - Request URL
|
|
567
|
+
- `params` (Hash, optional) - Query parameters
|
|
568
|
+
- `headers` (Hash, optional) - HTTP headers
|
|
569
|
+
|
|
570
|
+
**Returns:** `Net::HTTPResponse` object
|
|
571
|
+
|
|
359
572
|
#### `post(url, params: {}, headers: {}, body: nil)`
|
|
360
573
|
|
|
361
574
|
Convenience method for POST requests.
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Tiktok
|
|
4
|
+
module Open
|
|
5
|
+
module Omniauth
|
|
6
|
+
module Strategies
|
|
7
|
+
# OmniAuth strategy for TikTok Open Platform.
|
|
8
|
+
#
|
|
9
|
+
# Integrates TikTok OAuth2 authentication with OmniAuth.
|
|
10
|
+
#
|
|
11
|
+
# @example
|
|
12
|
+
# use OmniAuth::Builder do
|
|
13
|
+
# provider :tiktok_open, 'CLIENT_KEY', 'CLIENT_SECRET'
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
# Supported scopes and their user info fields:
|
|
17
|
+
# - user.info.basic: open_id, union_id, display_name, avatar_url, avatar_url_100, avatar_large_url
|
|
18
|
+
# - user.info.profile: profile_deep_link, bio_description, is_verified, username
|
|
19
|
+
# - user.info.stats: follower_count, following_count, likes_count, video_count
|
|
20
|
+
class TiktokOpenSdk < ::OmniAuth::Strategies::OAuth2
|
|
21
|
+
# Custom access token class for TikTok.
|
|
22
|
+
class AccessToken < ::OAuth2::AccessToken; end
|
|
23
|
+
|
|
24
|
+
# Maps TikTok OAuth scopes to user info fields.
|
|
25
|
+
SCOPE_FIELDS = {
|
|
26
|
+
'user.info.basic' => %w[open_id union_id display_name avatar_url avatar_url_100 avatar_large_url],
|
|
27
|
+
'user.info.profile' => %w[profile_deep_link bio_description is_verified username],
|
|
28
|
+
'user.info.stats' => %w[follower_count following_count likes_count video_count]
|
|
29
|
+
}.freeze
|
|
30
|
+
|
|
31
|
+
private_constant :SCOPE_FIELDS
|
|
32
|
+
|
|
33
|
+
# The name of this OmniAuth strategy.
|
|
34
|
+
option :name, :tiktok_open_sdk
|
|
35
|
+
|
|
36
|
+
# OAuth2 client options for TikTok endpoints.
|
|
37
|
+
# - :site: TikTok Open API base URL
|
|
38
|
+
# - :authorize_url: TikTok OAuth2 authorization endpoint
|
|
39
|
+
# - :token_url: TikTok OAuth2 token endpoint
|
|
40
|
+
option :client_options, {
|
|
41
|
+
site: ::Tiktok::Open::Sdk::Config::OPEN_API_BASE_URL,
|
|
42
|
+
authorize_url: ::Tiktok::Open::Sdk.config.user_auth.auth_url,
|
|
43
|
+
token_url: ::Tiktok::Open::Sdk.config.user_auth.token_url,
|
|
44
|
+
auth_scheme: :request_body,
|
|
45
|
+
auth_token_class: AccessToken
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
# List of parameters allowed in the authorization request.
|
|
49
|
+
option :authorize_options, %i[scope state redirect_uri]
|
|
50
|
+
|
|
51
|
+
# Default scope and redirect_uri from SDK config.
|
|
52
|
+
option :scope, ::Tiktok::Open::Sdk.config.user_auth.scopes.join(',')
|
|
53
|
+
option :redirect_uri, ::Tiktok::Open::Sdk.config.user_auth.redirect_uri
|
|
54
|
+
|
|
55
|
+
# Returns the unique TikTok user ID (open_id).
|
|
56
|
+
#
|
|
57
|
+
# @return [String] TikTok user's open_id.
|
|
58
|
+
uid { raw_info[:open_id].to_s }
|
|
59
|
+
|
|
60
|
+
# Returns a hash of user information.
|
|
61
|
+
#
|
|
62
|
+
# @return [Hash] User info with :name and :image keys, and profile fields if scope is present.
|
|
63
|
+
info do
|
|
64
|
+
{ name: raw_info[:display_name], image: raw_info[:avatar_url_100] }.tap do |info|
|
|
65
|
+
if request_scopes.include?('user.info.profile')
|
|
66
|
+
info.merge!(raw_info.slice(:username, :bio_description, :profile_deep_link))
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Returns extra raw user information from TikTok.
|
|
72
|
+
#
|
|
73
|
+
# @return [Hash] Raw user info data from TikTok API.
|
|
74
|
+
extra { raw_info }
|
|
75
|
+
|
|
76
|
+
# Returns the callback URL without query parameters.
|
|
77
|
+
#
|
|
78
|
+
# @return [String] Callback URL.
|
|
79
|
+
def callback_url
|
|
80
|
+
super.split('?').first
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Builds the access token from TikTok's token endpoint.
|
|
84
|
+
#
|
|
85
|
+
# @raise [OAuth2::Error] if the token response is unsuccessful.
|
|
86
|
+
# @return [AccessToken] OAuth2 access token object.
|
|
87
|
+
def build_access_token
|
|
88
|
+
response = fetch_access_token
|
|
89
|
+
validate_token_response(response)
|
|
90
|
+
create_access_token(response[:response])
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Handles the initial OAuth2 request phase.
|
|
94
|
+
#
|
|
95
|
+
# @raise [ArgumentError] if client_secret is present in params.
|
|
96
|
+
def request_phase
|
|
97
|
+
params = authorize_params.merge('response_type' => 'code')
|
|
98
|
+
|
|
99
|
+
if params.key?(:client_secret) || params.key?('client_secret')
|
|
100
|
+
raise ArgumentError, 'client_secret is not allowed in authorize URL query params'
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
redirect client.authorize_url(params)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Builds the authorization parameters for the OAuth2 request,
|
|
107
|
+
# adding the TikTok client_key.
|
|
108
|
+
#
|
|
109
|
+
# @return [Hash] Authorization parameters.
|
|
110
|
+
def authorize_params
|
|
111
|
+
super.tap do |params|
|
|
112
|
+
params[:client_key] = options.client_id
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
private
|
|
117
|
+
|
|
118
|
+
# Fetches access token from TikTok API
|
|
119
|
+
#
|
|
120
|
+
# @return [Hash] Token response from TikTok
|
|
121
|
+
def fetch_access_token
|
|
122
|
+
Tiktok::Open::Sdk.user_auth.fetch_access_token(
|
|
123
|
+
code: request.params['code'],
|
|
124
|
+
redirect_uri: callback_url
|
|
125
|
+
)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Validates the token response
|
|
129
|
+
#
|
|
130
|
+
# @param response [Hash] Token response
|
|
131
|
+
# @raise [OAuth2::Error] if response is unsuccessful
|
|
132
|
+
def validate_token_response(response)
|
|
133
|
+
raise OAuth2::Error, response[:response] unless response[:success]
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Creates AccessToken from response data
|
|
137
|
+
#
|
|
138
|
+
# @param data [Hash] Token data from response
|
|
139
|
+
# @return [AccessToken] OAuth2 access token object
|
|
140
|
+
def create_access_token(data)
|
|
141
|
+
AccessToken.from_hash(
|
|
142
|
+
client,
|
|
143
|
+
access_token: data[:access_token],
|
|
144
|
+
refresh_token: data[:refresh_token],
|
|
145
|
+
expires_at: Time.now.to_i + data[:expires_in].to_i
|
|
146
|
+
)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Returns the list of requested OAuth scopes.
|
|
150
|
+
#
|
|
151
|
+
# @return [Array<String>] List of scope strings.
|
|
152
|
+
def request_scopes
|
|
153
|
+
@request_scopes ||= request.params.fetch('scopes', 'user.info.basic').split(',')
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Returns the list of user info fields to request from TikTok,
|
|
157
|
+
# based on the requested scopes.
|
|
158
|
+
#
|
|
159
|
+
# @return [Array<String>] List of user info field names.
|
|
160
|
+
def user_info_fields
|
|
161
|
+
request_scopes.flat_map { |scope| SCOPE_FIELDS[scope] }.compact
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Fetches and memoizes the raw user info from the TikTok API.
|
|
165
|
+
#
|
|
166
|
+
# @return [Hash] Raw user info data, or empty hash if unavailable.
|
|
167
|
+
def raw_info
|
|
168
|
+
@raw_info ||= Tiktok::Open::Sdk.user.get_user_info(
|
|
169
|
+
access_token: access_token.token,
|
|
170
|
+
fields: user_info_fields
|
|
171
|
+
).dig(:response, :data, :user) || {}
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
@@ -13,44 +13,71 @@ module Tiktok
|
|
|
13
13
|
# config.client_secret = 'your_secret'
|
|
14
14
|
# config.user_auth.scopes = %w[user.info.basic]
|
|
15
15
|
class Config
|
|
16
|
-
#
|
|
16
|
+
# Base domains for constructing TikTok API URLs.
|
|
17
|
+
AUTH_BASE_URL = 'https://www.tiktok.com'
|
|
18
|
+
OPEN_API_BASE_URL = 'https://open.tiktokapis.com'
|
|
19
|
+
|
|
20
|
+
# @!attribute [rw] client_key
|
|
21
|
+
# @return [String] TikTok client key.
|
|
17
22
|
attr_accessor :client_key
|
|
18
23
|
|
|
19
|
-
#
|
|
24
|
+
# @!attribute [rw] client_secret
|
|
25
|
+
# @return [String] TikTok client secret.
|
|
20
26
|
attr_accessor :client_secret
|
|
21
27
|
|
|
22
|
-
#
|
|
28
|
+
# @!attribute [rw] user_info_url
|
|
29
|
+
# @return [String] TikTok user info endpoint URL.
|
|
30
|
+
attr_accessor :user_info_url
|
|
31
|
+
|
|
32
|
+
# @!attribute [rw] creator_info_query_url
|
|
33
|
+
# @return [String] TikTok Query Creator Info endpoint URL.
|
|
34
|
+
attr_accessor :creator_info_query_url
|
|
35
|
+
|
|
36
|
+
# @!attribute [rw] user_auth
|
|
37
|
+
# @return [UserAuth] User authentication configuration.
|
|
23
38
|
attr_accessor :user_auth
|
|
24
39
|
|
|
25
|
-
#
|
|
40
|
+
# @!attribute [rw] load_omniauth
|
|
41
|
+
# @return [Boolean] Whether to automatically load OmniAuth strategy.
|
|
42
|
+
attr_accessor :load_omniauth
|
|
43
|
+
|
|
44
|
+
# Create a new Config with default user authentication settings.
|
|
26
45
|
def initialize
|
|
27
|
-
@
|
|
46
|
+
@user_info_url = "#{OPEN_API_BASE_URL}/v2/user/info/"
|
|
47
|
+
@creator_info_query_url = "#{OPEN_API_BASE_URL}/v2/post/publish/creator_info/query/"
|
|
48
|
+
@user_auth = UserAuth.new
|
|
49
|
+
@load_omniauth = false
|
|
28
50
|
end
|
|
29
51
|
|
|
30
52
|
# User authentication configuration for TikTok Open SDK.
|
|
31
53
|
#
|
|
32
54
|
# Holds OAuth URLs, scopes, and redirect URI.
|
|
33
55
|
class UserAuth
|
|
34
|
-
#
|
|
56
|
+
# @!attribute [rw] auth_url
|
|
57
|
+
# @return [String] OAuth authorization URL.
|
|
35
58
|
attr_accessor :auth_url
|
|
36
59
|
|
|
37
|
-
#
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
# @return [String] The OAuth token revoke URL.
|
|
60
|
+
# @!attribute [rw] revoke_token_url
|
|
61
|
+
# @return [String] OAuth token revocation URL.
|
|
41
62
|
attr_accessor :revoke_token_url
|
|
42
63
|
|
|
43
|
-
#
|
|
64
|
+
# @!attribute [rw] token_url
|
|
65
|
+
# @return [String] OAuth token exchange URL.
|
|
66
|
+
attr_accessor :token_url
|
|
67
|
+
|
|
68
|
+
# @!attribute [rw] scopes
|
|
69
|
+
# @return [Array<String>] List of OAuth scopes.
|
|
44
70
|
attr_accessor :scopes
|
|
45
71
|
|
|
46
|
-
#
|
|
72
|
+
# @!attribute [rw] redirect_uri
|
|
73
|
+
# @return [String, nil] OAuth redirect URI.
|
|
47
74
|
attr_accessor :redirect_uri
|
|
48
75
|
|
|
49
76
|
# Initializes a new UserAuth object with default URLs and empty scopes.
|
|
50
77
|
def initialize
|
|
51
|
-
@auth_url =
|
|
52
|
-
@revoke_token_url =
|
|
53
|
-
@token_url =
|
|
78
|
+
@auth_url = "#{AUTH_BASE_URL}/v2/auth/authorize/"
|
|
79
|
+
@revoke_token_url = "#{OPEN_API_BASE_URL}/v2/oauth/revoke/"
|
|
80
|
+
@token_url = "#{OPEN_API_BASE_URL}/v2/oauth/token/"
|
|
54
81
|
@scopes = []
|
|
55
82
|
@redirect_uri = nil
|
|
56
83
|
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
|
|
5
|
+
module Tiktok
|
|
6
|
+
module Open
|
|
7
|
+
module Sdk
|
|
8
|
+
module Helpers
|
|
9
|
+
# Shared authentication helper methods for TikTok Open SDK auth modules.
|
|
10
|
+
module AuthHelper
|
|
11
|
+
private
|
|
12
|
+
|
|
13
|
+
# Returns the HTTP headers for requests.
|
|
14
|
+
#
|
|
15
|
+
# @return [Hash] The headers for HTTP requests.
|
|
16
|
+
def headers
|
|
17
|
+
{
|
|
18
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
19
|
+
'Cache-Control': 'no-cache'
|
|
20
|
+
}
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Returns the client credentials for authentication.
|
|
24
|
+
#
|
|
25
|
+
# @return [Hash] The client credentials.
|
|
26
|
+
def credentials
|
|
27
|
+
{
|
|
28
|
+
client_key: Tiktok::Open::Sdk.config.client_key,
|
|
29
|
+
client_secret: Tiktok::Open::Sdk.config.client_secret
|
|
30
|
+
}
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Returns the default query parameters for the authorization URI.
|
|
34
|
+
#
|
|
35
|
+
# @return [Hash] The default query parameters:
|
|
36
|
+
# - :client_key [String] The TikTok client key.
|
|
37
|
+
# - :response_type [String] Always 'code'.
|
|
38
|
+
# - :scope [String] Comma-separated scopes.
|
|
39
|
+
# - :redirect_uri [String] The redirect URI.
|
|
40
|
+
# - :state [nil] Default state is nil.
|
|
41
|
+
def authorization_uri_default_params
|
|
42
|
+
{
|
|
43
|
+
client_key: Tiktok::Open::Sdk.config.client_key,
|
|
44
|
+
response_type: 'code',
|
|
45
|
+
scope: Tiktok::Open::Sdk.config.user_auth.scopes.join(','),
|
|
46
|
+
redirect_uri: Tiktok::Open::Sdk.config.user_auth.redirect_uri,
|
|
47
|
+
state: nil
|
|
48
|
+
}
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# render_response moved to ::Tiktok::Open::Sdk::ResponseHelpers
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Tiktok
|
|
4
|
+
module Open
|
|
5
|
+
module Sdk
|
|
6
|
+
module Helpers
|
|
7
|
+
# Helper methods for formatting HTTP responses across the SDK.
|
|
8
|
+
module ResponseHelper
|
|
9
|
+
include ::Tiktok::Open::Sdk::Helpers::StringUtilsHelper
|
|
10
|
+
|
|
11
|
+
# Parses and formats the HTTP response.
|
|
12
|
+
#
|
|
13
|
+
# @param response [Net::HTTPResponse] The HTTP response object.
|
|
14
|
+
# @return [Hash] The formatted response with keys:
|
|
15
|
+
# - :success [Boolean] Whether the response is a Net::HTTPSuccess.
|
|
16
|
+
# - :code [Integer] HTTP status code.
|
|
17
|
+
# - :response [Hash] Parsed JSON body or a hash with the raw string if parsing fails.
|
|
18
|
+
def render_response(response)
|
|
19
|
+
{
|
|
20
|
+
success: response.is_a?(Net::HTTPSuccess),
|
|
21
|
+
code: response.code.to_i,
|
|
22
|
+
response: parse_json(response.body)
|
|
23
|
+
}
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
|
|
5
|
+
module Tiktok
|
|
6
|
+
module Open
|
|
7
|
+
module Sdk
|
|
8
|
+
module Helpers
|
|
9
|
+
# Utility methods for string and JSON handling.
|
|
10
|
+
module StringUtilsHelper
|
|
11
|
+
# Parses a JSON string into a Ruby hash with symbolized keys.
|
|
12
|
+
#
|
|
13
|
+
# @param str [String] JSON string to parse.
|
|
14
|
+
# @return [Hash] Parsed hash with symbolized keys, or a hash with the raw string if parsing fails.
|
|
15
|
+
def parse_json(str)
|
|
16
|
+
JSON.parse(str, symbolize_names: true)
|
|
17
|
+
rescue JSON::ParserError
|
|
18
|
+
{ raw: str }
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Tiktok
|
|
4
|
+
module Open
|
|
5
|
+
module Sdk
|
|
6
|
+
module Helpers
|
|
7
|
+
module Validators
|
|
8
|
+
# Provides token validation methods for TikTok Open SDK.
|
|
9
|
+
module TokenValidator
|
|
10
|
+
# Regular expression to validate tokens.
|
|
11
|
+
# Ensures the token consists of at least 10 printable characters.
|
|
12
|
+
TOKEN_REGEX = /\A[[:print:]]{10,}\z/
|
|
13
|
+
|
|
14
|
+
# Checks if the given token is a valid string of at least 10 printable characters.
|
|
15
|
+
#
|
|
16
|
+
# @param token [String] The token to check.
|
|
17
|
+
# @return [Boolean] true if the token is valid, false otherwise.
|
|
18
|
+
def valid_token?(token)
|
|
19
|
+
token.is_a?(String) && !token.empty? && TOKEN_REGEX.match?(token)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Validates the given token and raises an error if it is invalid.
|
|
23
|
+
#
|
|
24
|
+
# @param token [String] The token to validate.
|
|
25
|
+
# @raise [::Tiktok::Open::Sdk::RequestValidationError] if the token is invalid.
|
|
26
|
+
# @return [void]
|
|
27
|
+
def validate_token!(token)
|
|
28
|
+
return if valid_token?(token)
|
|
29
|
+
|
|
30
|
+
raise ::Tiktok::Open::Sdk::RequestValidationError,
|
|
31
|
+
'Invalid token format: must be at least 10 printable characters.'
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -13,8 +13,6 @@ module Tiktok
|
|
|
13
13
|
module HttpClient
|
|
14
14
|
extend self
|
|
15
15
|
|
|
16
|
-
include StringUtils
|
|
17
|
-
|
|
18
16
|
# Supported HTTP methods.
|
|
19
17
|
SUPPORTED_METHODS = %i[get post].freeze
|
|
20
18
|
|
|
@@ -53,6 +51,16 @@ module Tiktok
|
|
|
53
51
|
request(:post, url, params: params, headers: headers, body: body)
|
|
54
52
|
end
|
|
55
53
|
|
|
54
|
+
# Performs a GET HTTP request.
|
|
55
|
+
#
|
|
56
|
+
# @param url [String] The request URL.
|
|
57
|
+
# @param params [Hash] Query parameters.
|
|
58
|
+
# @param headers [Hash] HTTP headers.
|
|
59
|
+
# @return [Net::HTTPResponse] The HTTP response object.
|
|
60
|
+
def get(url, params: {}, headers: {})
|
|
61
|
+
request(:get, url, params: params, headers: headers)
|
|
62
|
+
end
|
|
63
|
+
|
|
56
64
|
private
|
|
57
65
|
|
|
58
66
|
# Ensures the HTTP method is supported.
|
|
@@ -77,7 +85,7 @@ module Tiktok
|
|
|
77
85
|
case content_type
|
|
78
86
|
when 'application/x-www-form-urlencoded'
|
|
79
87
|
request.set_form_data(body)
|
|
80
|
-
when 'application/json'
|
|
88
|
+
when 'application/json', 'application/json; charset=UTF-8'
|
|
81
89
|
request.body = body.to_json
|
|
82
90
|
else
|
|
83
91
|
raise ArgumentError, "Unsupported content type: #{content_type}"
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'uri'
|
|
4
|
-
|
|
5
3
|
module Tiktok
|
|
6
4
|
module Open
|
|
7
5
|
module Sdk
|
|
@@ -11,7 +9,8 @@ module Tiktok
|
|
|
11
9
|
module Client
|
|
12
10
|
extend self
|
|
13
11
|
|
|
14
|
-
include Helpers
|
|
12
|
+
include ::Tiktok::Open::Sdk::Helpers::AuthHelper
|
|
13
|
+
include ::Tiktok::Open::Sdk::Helpers::ResponseHelper
|
|
15
14
|
|
|
16
15
|
# Fetches a client access token from the TikTok Open API.
|
|
17
16
|
#
|
|
@@ -11,7 +11,8 @@ module Tiktok
|
|
|
11
11
|
module User
|
|
12
12
|
extend self
|
|
13
13
|
|
|
14
|
-
include Helpers
|
|
14
|
+
include ::Tiktok::Open::Sdk::Helpers::AuthHelper
|
|
15
|
+
include ::Tiktok::Open::Sdk::Helpers::ResponseHelper
|
|
15
16
|
|
|
16
17
|
# Constructs the TikTok OAuth authorization URI.
|
|
17
18
|
#
|
|
@@ -22,7 +23,7 @@ module Tiktok
|
|
|
22
23
|
# @return [URI] The constructed authorization URI.
|
|
23
24
|
def authorization_uri(params = {})
|
|
24
25
|
allowed_params = params.slice(:scope, :redirect_uri, :state)
|
|
25
|
-
uri = URI(Tiktok::Open::Sdk.config.user_auth.auth_url)
|
|
26
|
+
uri = URI.parse(Tiktok::Open::Sdk.config.user_auth.auth_url)
|
|
26
27
|
query_params = authorization_uri_default_params.merge(allowed_params)
|
|
27
28
|
uri.query = URI.encode_www_form(query_params)
|
|
28
29
|
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Provides methods to interact with TikTok Open API post endpoints.
|
|
4
|
+
module Tiktok
|
|
5
|
+
module Open
|
|
6
|
+
module Sdk
|
|
7
|
+
module OpenApi
|
|
8
|
+
module Post
|
|
9
|
+
# Provides methods for handling TikTok Open API post endpoints.
|
|
10
|
+
module Publish
|
|
11
|
+
extend self
|
|
12
|
+
|
|
13
|
+
include ::Tiktok::Open::Sdk::Helpers::ResponseHelper
|
|
14
|
+
include ::Tiktok::Open::Sdk::Helpers::Validators::TokenValidator
|
|
15
|
+
|
|
16
|
+
# Queries creator information from the TikTok Open API.
|
|
17
|
+
#
|
|
18
|
+
# @param access_token [String] OAuth2 access token for authentication.
|
|
19
|
+
# @return [Hash] Parsed API response containing creator information.
|
|
20
|
+
# @raise [::Tiktok::Open::Sdk::RequestValidationError] If the access token is invalid.
|
|
21
|
+
#
|
|
22
|
+
# @example
|
|
23
|
+
# Tiktok::Open::Sdk.post.creator_info_query(access_token: 'your_access_token')
|
|
24
|
+
def creator_info_query(access_token:)
|
|
25
|
+
validate_token!(access_token)
|
|
26
|
+
|
|
27
|
+
render_response Tiktok::Open::Sdk::HttpClient.post(
|
|
28
|
+
Tiktok::Open::Sdk.config.creator_info_query_url,
|
|
29
|
+
headers: {
|
|
30
|
+
Authorization: "Bearer #{access_token}"
|
|
31
|
+
}
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Provides methods to interact with TikTok Open API user endpoints.
|
|
4
|
+
module Tiktok
|
|
5
|
+
module Open
|
|
6
|
+
module Sdk
|
|
7
|
+
module OpenApi
|
|
8
|
+
# Provides user-related methods for the TikTok Open API.
|
|
9
|
+
module User
|
|
10
|
+
# List of valid user info fields that can be requested from the API.
|
|
11
|
+
FIELDS = %w[
|
|
12
|
+
open_id
|
|
13
|
+
union_id
|
|
14
|
+
avatar_url
|
|
15
|
+
avatar_url_100
|
|
16
|
+
avatar_large_url
|
|
17
|
+
display_name
|
|
18
|
+
bio_description
|
|
19
|
+
profile_deep_link
|
|
20
|
+
is_verified
|
|
21
|
+
username
|
|
22
|
+
follower_count
|
|
23
|
+
following_count
|
|
24
|
+
likes_count
|
|
25
|
+
video_count
|
|
26
|
+
].freeze
|
|
27
|
+
|
|
28
|
+
extend self
|
|
29
|
+
|
|
30
|
+
include ::Tiktok::Open::Sdk::Helpers::ResponseHelper
|
|
31
|
+
include ::Tiktok::Open::Sdk::Helpers::Validators::TokenValidator
|
|
32
|
+
|
|
33
|
+
# Retrieves user information from the TikTok Open API.
|
|
34
|
+
#
|
|
35
|
+
# @param access_token [String] OAuth2 access token for authentication.
|
|
36
|
+
# @param fields [Array<String>] User fields to retrieve. Must be a subset of FIELDS.
|
|
37
|
+
# @param validate [Boolean] Whether to validate the token and fields. Defaults to true.
|
|
38
|
+
# @return [Hash] Parsed API response containing user information.
|
|
39
|
+
# @raise [::Tiktok::Open::Sdk::RequestValidationError] If the access token or any requested field is invalid.
|
|
40
|
+
def get_user_info(access_token:, fields:, validate: true)
|
|
41
|
+
if validate
|
|
42
|
+
validate_token!(access_token)
|
|
43
|
+
validate_fields!(fields)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
render_response Tiktok::Open::Sdk::HttpClient.get(
|
|
47
|
+
Tiktok::Open::Sdk.config.user_info_url,
|
|
48
|
+
params: {
|
|
49
|
+
fields: fields.join(',')
|
|
50
|
+
},
|
|
51
|
+
headers: {
|
|
52
|
+
Authorization: "Bearer #{access_token}"
|
|
53
|
+
}
|
|
54
|
+
)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
# Ensures all requested fields are supported by the API.
|
|
60
|
+
#
|
|
61
|
+
# @param fields [Array<String>] Fields to validate against FIELDS.
|
|
62
|
+
# @raise [::Tiktok::Open::Sdk::RequestValidationError] If any field is not supported.
|
|
63
|
+
def validate_fields!(fields)
|
|
64
|
+
invalid = fields - FIELDS
|
|
65
|
+
|
|
66
|
+
return if invalid.empty?
|
|
67
|
+
|
|
68
|
+
raise ::Tiktok::Open::Sdk::RequestValidationError, "Invalid fields: #{invalid.join(", ")}"
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
data/lib/tiktok/open/sdk.rb
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative 'sdk/
|
|
4
|
-
|
|
5
|
-
require_relative 'sdk/
|
|
3
|
+
require_relative 'sdk/helpers/string_utils_helper'
|
|
4
|
+
require_relative 'sdk/helpers/response_helper'
|
|
5
|
+
require_relative 'sdk/helpers/auth_helper'
|
|
6
|
+
require_relative 'sdk/helpers/validators/token_validator'
|
|
6
7
|
require_relative 'sdk/open_api/auth/user'
|
|
7
8
|
require_relative 'sdk/open_api/auth/client'
|
|
9
|
+
require_relative 'sdk/open_api/post/publish'
|
|
10
|
+
require_relative 'sdk/open_api/user'
|
|
8
11
|
require_relative 'sdk/version'
|
|
9
12
|
require_relative 'sdk/http_client'
|
|
10
13
|
require_relative 'sdk/config'
|
|
@@ -19,6 +22,8 @@ module Tiktok
|
|
|
19
22
|
# raise Tiktok::Open::Sdk::Error, "Something went wrong"
|
|
20
23
|
class Error < StandardError; end
|
|
21
24
|
|
|
25
|
+
class RequestValidationError < Error; end
|
|
26
|
+
|
|
22
27
|
class << self
|
|
23
28
|
# SDK configuration object
|
|
24
29
|
#
|
|
@@ -41,12 +46,15 @@ module Tiktok
|
|
|
41
46
|
# config.user_auth.token_url = 'https://open.tiktokapis.com/v2/oauth/token/'
|
|
42
47
|
# config.user_auth.scopes = %w[user.info.basic video.list]
|
|
43
48
|
# config.user_auth.redirect_uri = 'https://your-redirect-uri.example.com'
|
|
49
|
+
# config.load_omniauth = true
|
|
44
50
|
# end
|
|
45
51
|
def configure
|
|
46
52
|
self.config ||= Config.new
|
|
47
53
|
|
|
48
54
|
yield(config)
|
|
49
55
|
|
|
56
|
+
load_omniauth! if config.load_omniauth
|
|
57
|
+
|
|
50
58
|
config
|
|
51
59
|
end
|
|
52
60
|
|
|
@@ -69,6 +77,44 @@ module Tiktok
|
|
|
69
77
|
def client_auth
|
|
70
78
|
OpenApi::Auth::Client
|
|
71
79
|
end
|
|
80
|
+
|
|
81
|
+
# Convenience accessor for post publish functionality
|
|
82
|
+
#
|
|
83
|
+
# @return [OpenApi::Post::Publish] the Post publish module
|
|
84
|
+
#
|
|
85
|
+
# @example
|
|
86
|
+
# Tiktok::Open::Sdk.post.video_init(access_token: 'token', post_info: post_info, source_info: source_info)
|
|
87
|
+
def post
|
|
88
|
+
OpenApi::Post::Publish
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Convenience accessor for user functionality
|
|
92
|
+
#
|
|
93
|
+
# @return [OpenApi::User] the User module
|
|
94
|
+
#
|
|
95
|
+
# @example
|
|
96
|
+
# Tiktok::Open::Sdk.user.info(access_token: 'token')
|
|
97
|
+
def user
|
|
98
|
+
OpenApi::User
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
private
|
|
102
|
+
|
|
103
|
+
# Loads the OmniAuth strategy for TikTok Open Platform.
|
|
104
|
+
#
|
|
105
|
+
# Attempts to require the necessary OmniAuth dependencies for TikTok Open integration.
|
|
106
|
+
# Raises an error if the required gems are not available.
|
|
107
|
+
#
|
|
108
|
+
# @raise [Tiktok::Open::Sdk::Error] if 'omniauth-oauth2' or the TikTok strategy cannot be loaded
|
|
109
|
+
# @example
|
|
110
|
+
# Tiktok::Open::Sdk.load_omniauth!
|
|
111
|
+
def load_omniauth!
|
|
112
|
+
require 'omniauth-oauth2'
|
|
113
|
+
require 'tiktok/open/omniauth/strategies/tiktok_open_sdk'
|
|
114
|
+
rescue LoadError => e
|
|
115
|
+
raise ::Tiktok::Open::Sdk::Error,
|
|
116
|
+
"OmniAuth is not loaded! Error: #{e.message}"
|
|
117
|
+
end
|
|
72
118
|
end
|
|
73
119
|
end
|
|
74
120
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tiktok-open-sdk
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Taras Pochkun
|
|
@@ -20,18 +20,24 @@ files:
|
|
|
20
20
|
- ".rspec"
|
|
21
21
|
- ".rubocop.yml"
|
|
22
22
|
- ".tool-versions"
|
|
23
|
+
- ".yardopts"
|
|
23
24
|
- CHANGELOG.md
|
|
24
25
|
- CODE_OF_CONDUCT.md
|
|
25
26
|
- LICENSE.txt
|
|
26
27
|
- README.md
|
|
27
28
|
- Rakefile
|
|
29
|
+
- lib/tiktok/open/omniauth/strategies/tiktok_open_sdk.rb
|
|
28
30
|
- lib/tiktok/open/sdk.rb
|
|
29
31
|
- lib/tiktok/open/sdk/config.rb
|
|
32
|
+
- lib/tiktok/open/sdk/helpers/auth_helper.rb
|
|
33
|
+
- lib/tiktok/open/sdk/helpers/response_helper.rb
|
|
34
|
+
- lib/tiktok/open/sdk/helpers/string_utils_helper.rb
|
|
35
|
+
- lib/tiktok/open/sdk/helpers/validators/token_validator.rb
|
|
30
36
|
- lib/tiktok/open/sdk/http_client.rb
|
|
31
37
|
- lib/tiktok/open/sdk/open_api/auth/client.rb
|
|
32
|
-
- lib/tiktok/open/sdk/open_api/auth/helpers.rb
|
|
33
38
|
- lib/tiktok/open/sdk/open_api/auth/user.rb
|
|
34
|
-
- lib/tiktok/open/sdk/
|
|
39
|
+
- lib/tiktok/open/sdk/open_api/post/publish.rb
|
|
40
|
+
- lib/tiktok/open/sdk/open_api/user.rb
|
|
35
41
|
- lib/tiktok/open/sdk/version.rb
|
|
36
42
|
- sig/tiktok/open/sdk.rbs
|
|
37
43
|
homepage: https://github.com/pochkuntaras/tiktok-open-sdk
|
|
@@ -40,9 +46,10 @@ licenses:
|
|
|
40
46
|
metadata:
|
|
41
47
|
allowed_push_host: https://rubygems.org
|
|
42
48
|
homepage_uri: https://github.com/pochkuntaras/tiktok-open-sdk
|
|
43
|
-
source_code_uri: https://github.com/pochkuntaras/tiktok-open-sdk
|
|
49
|
+
source_code_uri: https://github.com/pochkuntaras/tiktok-open-sdk.git
|
|
44
50
|
changelog_uri: https://github.com/pochkuntaras/tiktok-open-sdk/blob/main/CHANGELOG.md
|
|
45
51
|
rubygems_mfa_required: 'true'
|
|
52
|
+
documentation_uri: https://rubydoc.info/gems/tiktok-open-sdk
|
|
46
53
|
rdoc_options: []
|
|
47
54
|
require_paths:
|
|
48
55
|
- lib
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'json'
|
|
4
|
-
|
|
5
|
-
module Tiktok
|
|
6
|
-
module Open
|
|
7
|
-
module Sdk
|
|
8
|
-
module OpenApi
|
|
9
|
-
module Auth
|
|
10
|
-
# Shared authentication helper methods for TikTok Open SDK auth modules.
|
|
11
|
-
module Helpers
|
|
12
|
-
include StringUtils
|
|
13
|
-
|
|
14
|
-
private
|
|
15
|
-
|
|
16
|
-
# Returns the HTTP headers for requests.
|
|
17
|
-
#
|
|
18
|
-
# @return [Hash] The headers for HTTP requests.
|
|
19
|
-
def headers
|
|
20
|
-
{
|
|
21
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
22
|
-
'Cache-Control': 'no-cache'
|
|
23
|
-
}
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
# Returns the client credentials for authentication.
|
|
27
|
-
#
|
|
28
|
-
# @return [Hash] The client credentials.
|
|
29
|
-
def credentials
|
|
30
|
-
{
|
|
31
|
-
client_key: Tiktok::Open::Sdk.config.client_key,
|
|
32
|
-
client_secret: Tiktok::Open::Sdk.config.client_secret
|
|
33
|
-
}
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
# Returns the default query parameters for the authorization URI.
|
|
37
|
-
#
|
|
38
|
-
# @return [Hash] The default query parameters:
|
|
39
|
-
# - :client_key [String] The TikTok client key.
|
|
40
|
-
# - :response_type [String] Always 'code'.
|
|
41
|
-
# - :scope [String] Comma-separated scopes.
|
|
42
|
-
# - :redirect_uri [String] The redirect URI.
|
|
43
|
-
# - :state [nil] Default state is nil.
|
|
44
|
-
def authorization_uri_default_params
|
|
45
|
-
{
|
|
46
|
-
client_key: Tiktok::Open::Sdk.config.client_key,
|
|
47
|
-
response_type: 'code',
|
|
48
|
-
scope: Tiktok::Open::Sdk.config.user_auth.scopes.join(','),
|
|
49
|
-
redirect_uri: Tiktok::Open::Sdk.config.user_auth.redirect_uri,
|
|
50
|
-
state: nil
|
|
51
|
-
}
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
# Parses and formats the HTTP response.
|
|
55
|
-
#
|
|
56
|
-
# @param response [Net::HTTPResponse] The HTTP response object.
|
|
57
|
-
# @return [Hash] The formatted response with keys:
|
|
58
|
-
# - :success [Boolean] Whether the response is a Net::HTTPSuccess.
|
|
59
|
-
# - :code [Integer] HTTP status code.
|
|
60
|
-
# - :response [Hash] Parsed JSON body or a hash with the raw string if parsing fails.
|
|
61
|
-
def render_response(response)
|
|
62
|
-
{
|
|
63
|
-
success: response.is_a?(Net::HTTPSuccess),
|
|
64
|
-
code: response.code.to_i,
|
|
65
|
-
response: parse_json(response.body)
|
|
66
|
-
}
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
end
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'json'
|
|
4
|
-
|
|
5
|
-
module Tiktok
|
|
6
|
-
module Open
|
|
7
|
-
module Sdk
|
|
8
|
-
# Utility methods for string and JSON handling.
|
|
9
|
-
module StringUtils
|
|
10
|
-
module_function
|
|
11
|
-
|
|
12
|
-
# Parses a JSON string into a Ruby hash with symbolized keys.
|
|
13
|
-
#
|
|
14
|
-
# @param str [String] JSON string to parse.
|
|
15
|
-
# @return [Hash] Parsed hash with symbolized keys, or a hash with the raw string if parsing fails.
|
|
16
|
-
def parse_json(str)
|
|
17
|
-
JSON.parse(str, symbolize_names: true)
|
|
18
|
-
rescue JSON::ParserError
|
|
19
|
-
{ raw: str }
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|