tiktok-open-sdk 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 88676ada40b57b80a626dcd84747648a907360726b945d556e0701707bf562ff
4
+ data.tar.gz: 76505eb54c639643f46e9b111203f7871e73bf489bb49fdb10fb748b628d3238
5
+ SHA512:
6
+ metadata.gz: '0974ce3fed9eaeba6db5e5af1ca63d764bf1bcb0f83a733e9cb93447f7d9cb037e296968d362b4f82f371655cbb9ca26bfa83dd551878ae23435fc6be5229d7a'
7
+ data.tar.gz: 5a2adfcd6a265452739a5c9ba6cba9e281b229b47c91a5ea114fbd9c9546271e9b560795137a5be84ea91aae96ee4bbc3510efc885b4ff0b183e7bdceed3623a
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format progress
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,36 @@
1
+ plugins:
2
+ - rubocop-performance
3
+ - rubocop-rspec
4
+
5
+ AllCops:
6
+ TargetRubyVersion: 3.0
7
+ NewCops: enable
8
+ SuggestExtensions: false
9
+
10
+ Metrics/MethodLength:
11
+ Max: 15
12
+
13
+ Layout/HashAlignment:
14
+ EnforcedColonStyle: table
15
+ EnforcedHashRocketStyle: table
16
+
17
+ Style/StringLiterals:
18
+ EnforcedStyle: single_quotes
19
+
20
+ Style/StringLiteralsInInterpolation:
21
+ EnforcedStyle: double_quotes
22
+
23
+ RSpec/MultipleMemoizedHelpers:
24
+ Enabled: false
25
+
26
+ RSpec/NestedGroups:
27
+ Max: 4
28
+
29
+ RSpec/MultipleExpectations:
30
+ Max: 5
31
+
32
+ RSpec/ExampleLength:
33
+ Max: 12
34
+
35
+ Gemspec/DevelopmentDependencies:
36
+ Enabled: false
data/.tool-versions ADDED
@@ -0,0 +1 @@
1
+ ruby 3.4.4
data/CHANGELOG.md ADDED
@@ -0,0 +1,34 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2025-09-15
4
+
5
+ ### Added
6
+ - **OAuth 2.0 Authentication**
7
+ - Authorization URI generation with customizable scopes and redirect URIs
8
+ - Access token exchange and refresh functionality
9
+ - Token revocation support
10
+ - Comprehensive error handling
11
+
12
+ - **HTTP Client**
13
+ - GET and POST request support
14
+ - SSL/TLS handling for HTTPS URLs
15
+ - Query parameter encoding and form data support
16
+ - Custom headers and timeout configuration
17
+
18
+ - **Configuration**
19
+ - Easy SDK setup with client credentials
20
+ - Customizable OAuth endpoints
21
+ - Flexible scope and redirect URI management
22
+
23
+ - **Developer Experience**
24
+ - Complete Ruby documentation with examples
25
+ - Rails integration examples
26
+ - Test coverage
27
+ - RuboCop code quality enforcement
28
+ - MIT license
29
+
30
+ ### Technical Details
31
+ - **Ruby Support**: 2.7.0+
32
+ - **Dependencies**: Zero runtime dependencies
33
+ - **Testing**: RSpec with WebMock
34
+ - **Security**: Automated vulnerability scanning
@@ -0,0 +1,132 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our
6
+ community a harassment-free experience for everyone, regardless of age, body
7
+ size, visible or invisible disability, ethnicity, sex characteristics, gender
8
+ identity and expression, level of experience, education, socio-economic status,
9
+ nationality, personal appearance, race, caste, color, religion, or sexual
10
+ identity and orientation.
11
+
12
+ We pledge to act and interact in ways that contribute to an open, welcoming,
13
+ diverse, inclusive, and healthy community.
14
+
15
+ ## Our Standards
16
+
17
+ Examples of behavior that contributes to a positive environment for our
18
+ community include:
19
+
20
+ * Demonstrating empathy and kindness toward other people
21
+ * Being respectful of differing opinions, viewpoints, and experiences
22
+ * Giving and gracefully accepting constructive feedback
23
+ * Accepting responsibility and apologizing to those affected by our mistakes,
24
+ and learning from the experience
25
+ * Focusing on what is best not just for us as individuals, but for the overall
26
+ community
27
+
28
+ Examples of unacceptable behavior include:
29
+
30
+ * The use of sexualized language or imagery, and sexual attention or advances of
31
+ any kind
32
+ * Trolling, insulting or derogatory comments, and personal or political attacks
33
+ * Public or private harassment
34
+ * Publishing others' private information, such as a physical or email address,
35
+ without their explicit permission
36
+ * Other conduct which could reasonably be considered inappropriate in a
37
+ professional setting
38
+
39
+ ## Enforcement Responsibilities
40
+
41
+ Community leaders are responsible for clarifying and enforcing our standards of
42
+ acceptable behavior and will take appropriate and fair corrective action in
43
+ response to any behavior that they deem inappropriate, threatening, offensive,
44
+ or harmful.
45
+
46
+ Community leaders have the right and responsibility to remove, edit, or reject
47
+ comments, commits, code, wiki edits, issues, and other contributions that are
48
+ not aligned to this Code of Conduct, and will communicate reasons for moderation
49
+ decisions when appropriate.
50
+
51
+ ## Scope
52
+
53
+ This Code of Conduct applies within all community spaces, and also applies when
54
+ an individual is officially representing the community in public spaces.
55
+ Examples of representing our community include using an official email address,
56
+ posting via an official social media account, or acting as an appointed
57
+ representative at an online or offline event.
58
+
59
+ ## Enforcement
60
+
61
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
62
+ reported to the community leaders responsible for enforcement at
63
+ [INSERT CONTACT METHOD].
64
+ All complaints will be reviewed and investigated promptly and fairly.
65
+
66
+ All community leaders are obligated to respect the privacy and security of the
67
+ reporter of any incident.
68
+
69
+ ## Enforcement Guidelines
70
+
71
+ Community leaders will follow these Community Impact Guidelines in determining
72
+ the consequences for any action they deem in violation of this Code of Conduct:
73
+
74
+ ### 1. Correction
75
+
76
+ **Community Impact**: Use of inappropriate language or other behavior deemed
77
+ unprofessional or unwelcome in the community.
78
+
79
+ **Consequence**: A private, written warning from community leaders, providing
80
+ clarity around the nature of the violation and an explanation of why the
81
+ behavior was inappropriate. A public apology may be requested.
82
+
83
+ ### 2. Warning
84
+
85
+ **Community Impact**: A violation through a single incident or series of
86
+ actions.
87
+
88
+ **Consequence**: A warning with consequences for continued behavior. No
89
+ interaction with the people involved, including unsolicited interaction with
90
+ those enforcing the Code of Conduct, for a specified period of time. This
91
+ includes avoiding interactions in community spaces as well as external channels
92
+ like social media. Violating these terms may lead to a temporary or permanent
93
+ ban.
94
+
95
+ ### 3. Temporary Ban
96
+
97
+ **Community Impact**: A serious violation of community standards, including
98
+ sustained inappropriate behavior.
99
+
100
+ **Consequence**: A temporary ban from any sort of interaction or public
101
+ communication with the community for a specified period of time. No public or
102
+ private interaction with the people involved, including unsolicited interaction
103
+ with those enforcing the Code of Conduct, is allowed during this period.
104
+ Violating these terms may lead to a permanent ban.
105
+
106
+ ### 4. Permanent Ban
107
+
108
+ **Community Impact**: Demonstrating a pattern of violation of community
109
+ standards, including sustained inappropriate behavior, harassment of an
110
+ individual, or aggression toward or disparagement of classes of individuals.
111
+
112
+ **Consequence**: A permanent ban from any sort of public interaction within the
113
+ community.
114
+
115
+ ## Attribution
116
+
117
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118
+ version 2.1, available at
119
+ [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
120
+
121
+ Community Impact Guidelines were inspired by
122
+ [Mozilla's code of conduct enforcement ladder][Mozilla CoC].
123
+
124
+ For answers to common questions about this code of conduct, see the FAQ at
125
+ [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
126
+ [https://www.contributor-covenant.org/translations][translations].
127
+
128
+ [homepage]: https://www.contributor-covenant.org
129
+ [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
130
+ [Mozilla CoC]: https://github.com/mozilla/diversity
131
+ [FAQ]: https://www.contributor-covenant.org/faq
132
+ [translations]: https://www.contributor-covenant.org/translations
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Taras Pochkun
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,379 @@
1
+ # TikTok Open SDK
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/tiktok-open-sdk.svg)](https://badge.fury.io/rb/tiktok-open-sdk)
4
+ [![Ruby Version](https://img.shields.io/badge/ruby-%3E%3D%202.7.0-red.svg)](https://www.ruby-lang.org/en/downloads/)
5
+ [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE.txt)
6
+ [![CI](https://github.com/pochkuntaras/tiktok-open-sdk/actions/workflows/main.yml/badge.svg)](https://github.com/pochkuntaras/tiktok-open-sdk/actions/workflows/main.yml)
7
+
8
+ A comprehensive Ruby SDK for integrating with TikTok Open API. This gem provides OAuth 2.0 authentication, user authorization, and HTTP client functionality for accessing TikTok APIs seamlessly.
9
+
10
+ ## Features
11
+
12
+ - **OAuth 2.0 Authentication** – Seamless OAuth flow for secure integration
13
+ - **Token Management** – Easy access token exchange and refresh
14
+ - **HTTP Client** – Built-in client for interacting with TikTok APIs
15
+
16
+ ## Installation
17
+
18
+ Add this line to your application's Gemfile:
19
+
20
+ ```ruby
21
+ gem 'tiktok-open-sdk'
22
+ ```
23
+
24
+ And then execute:
25
+
26
+ ```bash
27
+ bundle install
28
+ ```
29
+
30
+ Or install it directly:
31
+
32
+ ```bash
33
+ gem install tiktok-open-sdk
34
+ ```
35
+
36
+ ## Configuration
37
+
38
+ Before using the SDK, you need to configure it with your TikTok app credentials:
39
+
40
+ ```ruby
41
+ require 'tiktok/open/sdk'
42
+
43
+ Tiktok::Open::Sdk.configure do |config|
44
+ # Required: Your TikTok app credentials
45
+ config.client_key = 'your_client_key'
46
+ config.client_secret = 'your_client_secret'
47
+
48
+ # Optional: Customize OAuth settings
49
+ config.user_auth.scopes = %w[user.info.basic video.list]
50
+ config.user_auth.redirect_uri = 'https://your-app.com/auth/callback'
51
+
52
+ # Optional: Custom URLs (defaults are provided)
53
+ config.user_auth.auth_url = 'https://www.tiktok.com/v2/auth/authorize/'
54
+ config.user_auth.token_url = 'https://open.tiktokapis.com/v2/oauth/token/'
55
+ config.user_auth.revoke_token_url = 'https://open.tiktokapis.com/v2/oauth/revoke/'
56
+ end
57
+ ```
58
+
59
+ ### Getting TikTok App Credentials
60
+
61
+ 1. Visit [TikTok for Developers](https://developers.tiktok.com/)
62
+ 2. Create a new app or use an existing one
63
+ 3. Navigate to your app's settings
64
+ 4. Copy your **Client Key** and **Client Secret**
65
+
66
+ ## Usage
67
+
68
+ ### Basic OAuth Flow
69
+
70
+ #### 1. Generate Authorization URI
71
+
72
+ ```ruby
73
+ # Generate the authorization URI for user login
74
+ auth_uri = Tiktok::Open::Sdk.user_auth.authorization_uri
75
+
76
+ # Or with custom parameters
77
+ auth_uri = Tiktok::Open::Sdk.user_auth.authorization_uri(
78
+ scope: 'user.info.basic,video.list',
79
+ redirect_uri: 'https://your-app.com/callback',
80
+ state: 'random_state_string'
81
+ )
82
+
83
+ puts auth_uri.to_s
84
+ # => "https://www.tiktok.com/v2/auth/authorize/?client_key=your_key&response_type=code&scope=user.info.basic&redirect_uri=https://your-app.com/callback"
85
+ ```
86
+
87
+ #### 2. Handle Authorization Callback
88
+
89
+ After the user authorizes your app, TikTok will redirect to your `redirect_uri` with an authorization code:
90
+
91
+ ```ruby
92
+ # Extract the code from the callback URL
93
+ code = params[:code] # From your web framework (Rails, Sinatra, etc.)
94
+
95
+ # Exchange the code for an access token
96
+ response = Tiktok::Open::Sdk.user_auth.fetch_access_token(code: code)
97
+
98
+ if response[:success]
99
+ access_token = response[:response]['access_token']
100
+ refresh_token = response[:response]['refresh_token']
101
+ expires_in = response[:response]['expires_in']
102
+
103
+ puts "Access Token: #{access_token}"
104
+ puts "Refresh Token: #{refresh_token}"
105
+ puts "Expires in: #{expires_in} seconds"
106
+ else
107
+ puts "Error: #{response[:response]}"
108
+ end
109
+ ```
110
+
111
+ #### 3. Refresh Access Token
112
+
113
+ ```ruby
114
+ # Refresh an expired access token
115
+ response = Tiktok::Open::Sdk.user_auth.refresh_access_token(
116
+ refresh_token: 'your_refresh_token'
117
+ )
118
+
119
+ if response[:success]
120
+ new_access_token = response[:response]['access_token']
121
+
122
+ puts "New Access Token: #{new_access_token}"
123
+ end
124
+ ```
125
+
126
+ #### 4. Revoke Access Token
127
+
128
+ ```ruby
129
+ # Revoke a refresh token
130
+ response = Tiktok::Open::Sdk.user_auth.revoke_access_token(
131
+ token: 'your_refresh_token'
132
+ )
133
+
134
+ puts "Token revoked successfully" if response[:success]
135
+ ```
136
+
137
+ ### Using the HTTP Client
138
+
139
+ The SDK includes a flexible HTTP client for making API calls:
140
+
141
+ ```ruby
142
+ # GET request
143
+ response = Tiktok::Open::Sdk::HttpClient.request(
144
+ :get,
145
+ 'https://open.tiktokapis.com/v2/user/info/',
146
+ params: {
147
+ fields: 'open_id,union_id,avatar_url'
148
+ },
149
+ headers: {
150
+ 'Authorization' => "Bearer #{access_token}"
151
+ }
152
+ )
153
+
154
+ # POST request
155
+ response = Tiktok::Open::Sdk::HttpClient.post(
156
+ 'https://open.tiktokapis.com/v2/video/list/',
157
+ headers: {
158
+ 'Authorization' => "Bearer #{access_token}",
159
+ 'Content-Type' => 'application/json'
160
+ },
161
+ body: {
162
+ max_count: 10,
163
+ cursor: 0
164
+ }
165
+ )
166
+
167
+ # Check response
168
+ if response.is_a?(Net::HTTPSuccess)
169
+ data = JSON.parse(response.body)
170
+
171
+ puts "Success: #{data}"
172
+ else
173
+ puts "Error: #{response.code} - #{response.body}"
174
+ end
175
+ ```
176
+
177
+ ### Complete Rails Example
178
+
179
+ Here's a complete example for a Rails application:
180
+
181
+ ```ruby
182
+ # config/initializers/tiktok_sdk.rb
183
+ require 'tiktok/open/sdk'
184
+
185
+ Tiktok::Open::Sdk.configure do |config|
186
+ config.client_key = Rails.application.credentials.tiktok_client_key
187
+ config.client_secret = Rails.application.credentials.tiktok_client_secret
188
+ config.user_auth.scopes = %w[user.info.basic video.list]
189
+ config.user_auth.redirect_uri = "#{Rails.application.routes.url_helpers.root_url}auth/tiktok/callback"
190
+ end
191
+ ```
192
+
193
+ ```ruby
194
+ # app/controllers/tiktok_auth_controller.rb
195
+ class TiktokAuthController < ApplicationController
196
+ def login
197
+ # Generate authorization URI
198
+ auth_uri = Tiktok::Open::Sdk.user_auth.authorization_uri(
199
+ state: session[:state] = SecureRandom.hex(16)
200
+ )
201
+
202
+ redirect_to auth_uri.to_s
203
+ end
204
+
205
+ def callback
206
+ # Verify state parameter for CSRF protection
207
+ if params[:state] != session[:state]
208
+ redirect_to root_path, alert: 'Invalid state parameter'
209
+
210
+ return
211
+ end
212
+
213
+ # Exchange code for access token
214
+ response = Tiktok::Open::Sdk.user_auth.fetch_access_token(code: params[:code])
215
+
216
+ if response[:success]
217
+ token_data = response[:response]
218
+
219
+ # Store tokens securely (consider using encrypted attributes)
220
+ session[:tiktok_access_token] = token_data['access_token']
221
+ session[:tiktok_refresh_token] = token_data['refresh_token']
222
+
223
+ redirect_to dashboard_path, notice: 'Successfully connected to TikTok!'
224
+ else
225
+ redirect_to root_path, alert: 'Failed to authenticate with TikTok'
226
+ end
227
+ end
228
+
229
+ def disconnect
230
+ if session[:tiktok_refresh_token]
231
+ Tiktok::Open::Sdk.user_auth.revoke_access_token(
232
+ token: session[:tiktok_refresh_token]
233
+ )
234
+ end
235
+
236
+ session.delete(:tiktok_access_token)
237
+ session.delete(:tiktok_refresh_token)
238
+
239
+ redirect_to root_path, notice: 'Disconnected from TikTok'
240
+ end
241
+ end
242
+ ```
243
+
244
+ ## API Reference
245
+
246
+ ### Configuration
247
+
248
+ #### `Tiktok::Open::Sdk.configure`
249
+
250
+ Configures the SDK with your app credentials and settings.
251
+
252
+ ```ruby
253
+ Tiktok::Open::Sdk.configure do |config|
254
+ config.client_key = 'your_client_key' # Required
255
+ config.client_secret = 'your_client_secret' # Required
256
+ config.user_auth.scopes = %w[user.info.basic] # Optional
257
+ config.user_auth.redirect_uri = 'https://...' # Optional
258
+ end
259
+ ```
260
+
261
+ ### User Authentication
262
+
263
+ #### `authorization_uri(params = {})`
264
+
265
+ Generates the OAuth authorization URI.
266
+
267
+ **Parameters:**
268
+ - `scope` (String, optional) - Comma-separated scopes
269
+ - `redirect_uri` (String, optional) - Custom redirect URI
270
+ - `state` (String, optional) - State parameter for CSRF protection
271
+
272
+ **Returns:** `URI` object
273
+
274
+ #### `fetch_access_token(code:, redirect_uri: nil)`
275
+
276
+ Exchanges authorization code for access token.
277
+
278
+ **Parameters:**
279
+ - `code` (String, required) - Authorization code from callback
280
+ - `redirect_uri` (String, optional) - Redirect URI used in authorization
281
+
282
+ **Returns:** Hash with `:success`, `:code`, and `:response` keys
283
+
284
+ #### `refresh_access_token(refresh_token:)`
285
+
286
+ Refreshes an expired access token.
287
+
288
+ **Parameters:**
289
+ - `refresh_token` (String, required) - Refresh token
290
+
291
+ **Returns:** Hash with `:success`, `:code`, and `:response` keys
292
+
293
+ #### `revoke_access_token(token:)`
294
+
295
+ Revokes a refresh token.
296
+
297
+ **Parameters:**
298
+ - `token` (String, required) - Refresh token to revoke
299
+
300
+ **Returns:** Hash with `:success`, `:code`, and `:response` keys
301
+
302
+ ### HTTP Client
303
+
304
+ #### `request(method, url, params: {}, headers: {}, body: nil)`
305
+
306
+ Performs HTTP requests.
307
+
308
+ **Parameters:**
309
+ - `method` (Symbol) - HTTP method (`:get`, `:post`)
310
+ - `url` (String) - Request URL
311
+ - `params` (Hash, optional) - Query parameters
312
+ - `headers` (Hash, optional) - HTTP headers
313
+ - `body` (Hash, optional) - Request body
314
+
315
+ **Returns:** `Net::HTTPResponse` object
316
+
317
+ #### `post(url, params: {}, headers: {}, body: nil)`
318
+
319
+ Convenience method for POST requests.
320
+
321
+ ## Development
322
+
323
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
324
+
325
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
326
+
327
+ ### Running Tests
328
+
329
+ ```bash
330
+ # Run all tests
331
+ bundle exec rspec
332
+
333
+ # Run tests with coverage
334
+ bundle exec rspec --format documentation
335
+ ```
336
+
337
+ ### Code Quality
338
+
339
+ This project uses RuboCop for code quality:
340
+
341
+ ```bash
342
+ # Check code style
343
+ bundle exec rubocop
344
+
345
+ # Auto-fix issues
346
+ bundle exec rubocop -a
347
+ ```
348
+
349
+ ## Contributing
350
+
351
+ Bug reports and pull requests are welcome on GitHub at https://github.com/pochkuntaras/tiktok-open-sdk. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](CODE_OF_CONDUCT.md).
352
+
353
+ ### Development Setup
354
+
355
+ 1. Fork the repository
356
+ 2. Clone your fork: `git clone https://github.com/your-username/tiktok-open-sdk.git`
357
+ 3. Install dependencies: `bundle install`
358
+ 4. Create a feature branch: `git checkout -b feature-name`
359
+ 5. Make your changes and add tests
360
+ 6. Run tests: `bundle exec rspec`
361
+ 7. Check code style: `bundle exec rubocop`
362
+ 8. Commit your changes: `git commit -am 'Add some feature'`
363
+ 9. Push to the branch: `git push origin feature-name`
364
+ 10. Submit a pull request
365
+
366
+ ## License
367
+
368
+ The gem is available as open source under the terms of the [MIT License](LICENSE.txt).
369
+
370
+ ## Links
371
+
372
+ - [TikTok for Developers](https://developers.tiktok.com/)
373
+ - [TikTok Open API Documentation](https://developers.tiktok.com/doc/)
374
+ - [RubyGems Page](https://rubygems.org/gems/tiktok-open-sdk)
375
+ - [GitHub Repository](https://github.com/pochkuntaras/tiktok-open-sdk)
376
+
377
+ ## Changelog
378
+
379
+ See [CHANGELOG.md](CHANGELOG.md) for a list of changes and version history.
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require 'rubocop/rake_task'
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ desc 'Run security audit'
13
+ task :audit do
14
+ system('bundle-audit check --update')
15
+ end
16
+
17
+ task default: %i[spec rubocop audit]
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tiktok
4
+ module Open
5
+ module Sdk
6
+ # Configuration class for TikTok Open SDK.
7
+ #
8
+ # Holds client credentials and user authentication settings.
9
+ #
10
+ # @example
11
+ # config = Tiktok::Open::Sdk::Config.new
12
+ # config.client_key = 'your_key'
13
+ # config.client_secret = 'your_secret'
14
+ # config.user_auth.scopes = %w[user.info.basic]
15
+ class Config
16
+ # @return [String] The TikTok client key.
17
+ attr_accessor :client_key
18
+
19
+ # @return [String] The TikTok client secret.
20
+ attr_accessor :client_secret
21
+
22
+ # @return [UserAuth] The user authentication configuration.
23
+ attr_accessor :user_auth
24
+
25
+ # Initializes a new Config object with default user authentication settings.
26
+ def initialize
27
+ @user_auth = UserAuth.new
28
+ end
29
+
30
+ # User authentication configuration for TikTok Open SDK.
31
+ #
32
+ # Holds OAuth URLs, scopes, and redirect URI.
33
+ class UserAuth
34
+ # @return [String] The OAuth authorization URL.
35
+ attr_accessor :auth_url
36
+
37
+ # @return [String] The OAuth token exchange URL.
38
+ attr_accessor :token_url
39
+
40
+ # @return [String] The OAuth token revoke URL.
41
+ attr_accessor :revoke_token_url
42
+
43
+ # @return [Array<String>] The list of OAuth scopes.
44
+ attr_accessor :scopes
45
+
46
+ # @return [String, nil] The OAuth redirect URI.
47
+ attr_accessor :redirect_uri
48
+
49
+ # Initializes a new UserAuth object with default URLs and empty scopes.
50
+ def initialize
51
+ @auth_url = 'https://www.tiktok.com/v2/auth/authorize/'
52
+ @revoke_token_url = 'https://open.tiktokapis.com/v2/oauth/revoke/'
53
+ @token_url = 'https://open.tiktokapis.com/v2/oauth/token/'
54
+ @scopes = []
55
+ @redirect_uri = nil
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/http'
4
+ require 'json'
5
+ require 'uri'
6
+
7
+ module Tiktok
8
+ module Open
9
+ module Sdk
10
+ # HTTP client utilities for TikTok Open SDK.
11
+ #
12
+ # Provides methods to perform HTTP requests with support for GET and POST.
13
+ module HttpClient
14
+ extend self
15
+
16
+ include StringUtils
17
+
18
+ # Supported HTTP methods.
19
+ SUPPORTED_METHODS = %i[get post].freeze
20
+
21
+ # Performs an HTTP request.
22
+ #
23
+ # @param method [Symbol] The HTTP method (:get, :post).
24
+ # @param url [String] The request URL.
25
+ # @param params [Hash] Query parameters for GET requests.
26
+ # @param headers [Hash] HTTP headers.
27
+ # @param body [Hash, nil] Request body for POST requests.
28
+ # @return [Net::HTTPResponse] The HTTP response object.
29
+ # @raise [ArgumentError] If the method is not supported.
30
+ def request(method, url, params: {}, headers: {}, body: nil)
31
+ ensure_supported_method!(method)
32
+
33
+ uri = URI(url)
34
+ uri.query = URI.encode_www_form(params) if method == :get && params.any?
35
+
36
+ http = Net::HTTP.new(uri.host, uri.port)
37
+ http.use_ssl = uri.scheme == 'https'
38
+ http.read_timeout = 10
39
+ http.open_timeout = 5
40
+ http_request = build_http_request(method, uri, headers, body)
41
+
42
+ http.request(http_request)
43
+ end
44
+
45
+ # Performs a POST HTTP request.
46
+ #
47
+ # @param url [String] The request URL.
48
+ # @param params [Hash] Query parameters.
49
+ # @param headers [Hash] HTTP headers.
50
+ # @param body [Hash, nil] Request body.
51
+ # @return [Net::HTTPResponse] The HTTP response object.
52
+ def post(url, params: {}, headers: {}, body: nil)
53
+ request(:post, url, params: params, headers: headers, body: body)
54
+ end
55
+
56
+ private
57
+
58
+ # Ensures the HTTP method is supported.
59
+ #
60
+ # @param method [Symbol] The HTTP method.
61
+ # @return [true] If the method is supported.
62
+ # @raise [ArgumentError] If the method is not supported.
63
+ def ensure_supported_method!(method)
64
+ return true if SUPPORTED_METHODS.include?(method)
65
+
66
+ raise ArgumentError, "Unsupported method: #{method}"
67
+ end
68
+
69
+ # Assigns the request body based on content type.
70
+ #
71
+ # @param request [Net::HTTPRequest] The HTTP request object.
72
+ # @param body [Hash] The request body.
73
+ # @param content_type [String] The content type header.
74
+ # @return [Net::HTTPRequest] The modified request object.
75
+ # @raise [ArgumentError] If the content type is unsupported.
76
+ def assign_body!(request, body, content_type)
77
+ case content_type
78
+ when 'application/x-www-form-urlencoded'
79
+ request.set_form_data(body)
80
+ when 'application/json'
81
+ request.body = body.to_json
82
+ else
83
+ raise ArgumentError, "Unsupported content type: #{content_type}"
84
+ end
85
+
86
+ request
87
+ end
88
+
89
+ # Builds the Net::HTTP request object.
90
+ #
91
+ # @param method [Symbol] The HTTP method.
92
+ # @param uri [URI] The request URI.
93
+ # @param headers [Hash] HTTP headers.
94
+ # @param body [Hash, nil] The request body.
95
+ # @return [Net::HTTPRequest] The HTTP request object.
96
+ def build_http_request(method, uri, headers, body)
97
+ klass = Net::HTTP.const_get(method.capitalize)
98
+ request = klass.new(uri, headers)
99
+
100
+ body ? assign_body!(request, body, headers[:'Content-Type']) : request
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,145 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'uri'
4
+
5
+ module Tiktok
6
+ module Open
7
+ module Sdk
8
+ module OpenApi
9
+ module Auth
10
+ # Provides user authentication helper methods for the TikTok Open SDK.
11
+ module User
12
+ extend self
13
+
14
+ include StringUtils
15
+
16
+ # Constructs the TikTok OAuth authorization URI.
17
+ #
18
+ # @param params [Hash] Optional query parameters to override defaults.
19
+ # - :scope [String] (optional) Comma-separated scopes to request.
20
+ # - :redirect_uri [String] (optional) Redirect URI for the OAuth callback.
21
+ # - :state [String] (optional) State parameter for CSRF protection.
22
+ # @return [URI] The constructed authorization URI.
23
+ def authorization_uri(params = {})
24
+ allowed_params = params.slice(:scope, :redirect_uri, :state)
25
+ uri = URI(Tiktok::Open::Sdk.config.user_auth.auth_url)
26
+ query_params = authorization_uri_default_params.merge(allowed_params)
27
+ uri.query = URI.encode_www_form(query_params)
28
+
29
+ uri
30
+ end
31
+
32
+ # Exchanges an authorization code for an access token.
33
+ #
34
+ # @param code [String] The authorization code received from TikTok.
35
+ # @param redirect_uri [String] The redirect URI used in the authorization request.
36
+ # Defaults to the configured redirect URI.
37
+ # @return [Hash] The parsed response, including:
38
+ # - :success [Boolean] Whether the request was successful.
39
+ # - :code [Integer] HTTP status code.
40
+ # - :response [Hash] Parsed response body or raw string if parsing fails.
41
+ def fetch_access_token(code:, redirect_uri: Tiktok::Open::Sdk.config.user_auth.redirect_uri)
42
+ render_response Tiktok::Open::Sdk::HttpClient.post(
43
+ Tiktok::Open::Sdk.config.user_auth.token_url,
44
+ headers: headers,
45
+ body: credentials.merge(
46
+ code: code,
47
+ grant_type: 'authorization_code',
48
+ redirect_uri: redirect_uri
49
+ )
50
+ )
51
+ end
52
+
53
+ # Exchanges a refresh token for a new access token.
54
+ #
55
+ # @param refresh_token [String] The refresh token issued by TikTok.
56
+ # @return [Hash] The parsed response, including:
57
+ # - :success [Boolean] Whether the request was successful.
58
+ # - :code [Integer] HTTP status code.
59
+ # - :response [Hash] Parsed response body or raw string if parsing fails.
60
+ def refresh_access_token(refresh_token:)
61
+ render_response Tiktok::Open::Sdk::HttpClient.post(
62
+ Tiktok::Open::Sdk.config.user_auth.token_url,
63
+ headers: headers,
64
+ body: credentials.merge(
65
+ grant_type: 'refresh_token',
66
+ refresh_token: refresh_token
67
+ )
68
+ )
69
+ end
70
+
71
+ # Revokes an access token using the provided refresh token.
72
+ #
73
+ # @param token [String] The refresh token to revoke.
74
+ # @return [Hash] The parsed response, including:
75
+ # - :success [Boolean] Whether the request was successful.
76
+ # - :code [Integer] HTTP status code.
77
+ # - :response [Hash] Parsed response body or raw string if parsing fails.
78
+ def revoke_access_token(token:)
79
+ render_response Tiktok::Open::Sdk::HttpClient.post(
80
+ Tiktok::Open::Sdk.config.user_auth.revoke_token_url,
81
+ headers: headers,
82
+ body: credentials.merge(token: token)
83
+ )
84
+ end
85
+
86
+ private
87
+
88
+ # Returns the HTTP headers for requests.
89
+ #
90
+ # @return [Hash] The headers for HTTP requests.
91
+ def headers
92
+ {
93
+ 'Content-Type': 'application/x-www-form-urlencoded',
94
+ 'Cache-Control': 'no-cache'
95
+ }
96
+ end
97
+
98
+ # Returns the client credentials for authentication.
99
+ #
100
+ # @return [Hash] The client credentials.
101
+ def credentials
102
+ {
103
+ client_key: Tiktok::Open::Sdk.config.client_key,
104
+ client_secret: Tiktok::Open::Sdk.config.client_secret
105
+ }
106
+ end
107
+
108
+ # Returns the default query parameters for the authorization URI.
109
+ #
110
+ # @return [Hash] The default query parameters:
111
+ # - :client_key [String] The TikTok client key.
112
+ # - :response_type [String] Always 'code'.
113
+ # - :scope [String] Comma-separated scopes.
114
+ # - :redirect_uri [String] The redirect URI.
115
+ # - :state [nil] Default state is nil.
116
+ def authorization_uri_default_params
117
+ {
118
+ client_key: Tiktok::Open::Sdk.config.client_key,
119
+ response_type: 'code',
120
+ scope: Tiktok::Open::Sdk.config.user_auth.scopes.join(','),
121
+ redirect_uri: Tiktok::Open::Sdk.config.user_auth.redirect_uri,
122
+ state: nil
123
+ }
124
+ end
125
+
126
+ # Parses and formats the HTTP response.
127
+ #
128
+ # @param response [Net::HTTPResponse] The HTTP response object.
129
+ # @return [Hash] The formatted response with keys:
130
+ # - :success [Boolean] Whether the response is a Net::HTTPSuccess.
131
+ # - :code [Integer] HTTP status code.
132
+ # - :response [Hash] Parsed JSON body or a hash with the raw string if parsing fails.
133
+ def render_response(response)
134
+ {
135
+ success: response.is_a?(Net::HTTPSuccess),
136
+ code: response.code.to_i,
137
+ response: parse_json(response.body)
138
+ }
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
144
+ end
145
+ 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
+ # 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
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tiktok
4
+ module Open
5
+ module Sdk
6
+ VERSION = '0.1.0'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'sdk/string_utils'
4
+
5
+ require_relative 'sdk/open_api/auth/user'
6
+ require_relative 'sdk/version'
7
+ require_relative 'sdk/http_client'
8
+ require_relative 'sdk/config'
9
+
10
+ module Tiktok
11
+ module Open
12
+ # Main SDK module providing configuration and error handling
13
+ module Sdk
14
+ # Generic error class for TikTok Open SDK
15
+ #
16
+ # @example
17
+ # raise Tiktok::Open::Sdk::Error, "Something went wrong"
18
+ class Error < StandardError; end
19
+
20
+ class << self
21
+ # SDK configuration object
22
+ #
23
+ # @return [Config, nil]
24
+ attr_accessor :config
25
+
26
+ # Configures the TikTok Open SDK.
27
+ #
28
+ # This method yields the configuration object, allowing you to set
29
+ # client credentials and other options.
30
+ #
31
+ # @yieldparam config [Config] the configuration object
32
+ # @return [Config] the configured object
33
+ #
34
+ # @example
35
+ # Tiktok::Open::Sdk.configure do |config|
36
+ # config.client_key = 'your_key'
37
+ # config.client_secret = 'your_secret'
38
+ # config.user_auth.auth_url = 'https://www.tiktok.com/v2/auth/authorize/'
39
+ # config.user_auth.token_url = 'https://open.tiktokapis.com/v2/oauth/token/'
40
+ # config.user_auth.scopes = %w[user.info.basic video.list]
41
+ # config.user_auth.redirect_uri = 'https://your-redirect-uri.example.com'
42
+ # end
43
+ def configure
44
+ self.config ||= Config.new
45
+
46
+ yield(config)
47
+
48
+ config
49
+ end
50
+
51
+ # Convenience accessor for user authentication functionality
52
+ #
53
+ # @return [OpenApi::Auth::User] the User authentication module
54
+ #
55
+ # @example
56
+ # Tiktok::Open::Sdk.user_auth.authorization_uri
57
+ def user_auth
58
+ OpenApi::Auth::User
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,8 @@
1
+ module Tiktok
2
+ module Open
3
+ module Sdk
4
+ VERSION: String
5
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
6
+ end
7
+ end
8
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tiktok-open-sdk
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Taras Pochkun
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies: []
12
+ description: A comprehensive Ruby SDK for integrating with TikTok Open API. Provides
13
+ OAuth 2.0 authentication, user authorization, and HTTP client functionality.
14
+ email:
15
+ - pochkun.t@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".rspec"
21
+ - ".rubocop.yml"
22
+ - ".tool-versions"
23
+ - CHANGELOG.md
24
+ - CODE_OF_CONDUCT.md
25
+ - LICENSE.txt
26
+ - README.md
27
+ - Rakefile
28
+ - lib/tiktok/open/sdk.rb
29
+ - lib/tiktok/open/sdk/config.rb
30
+ - lib/tiktok/open/sdk/http_client.rb
31
+ - lib/tiktok/open/sdk/open_api/auth/user.rb
32
+ - lib/tiktok/open/sdk/string_utils.rb
33
+ - lib/tiktok/open/sdk/version.rb
34
+ - sig/tiktok/open/sdk.rbs
35
+ homepage: https://github.com/pochkuntaras/tiktok-open-sdk
36
+ licenses:
37
+ - MIT
38
+ metadata:
39
+ allowed_push_host: https://rubygems.org
40
+ homepage_uri: https://github.com/pochkuntaras/tiktok-open-sdk
41
+ source_code_uri: https://github.com/pochkuntaras/tiktok-open-sdk
42
+ changelog_uri: https://github.com/pochkuntaras/tiktok-open-sdk/blob/main/CHANGELOG.md
43
+ rubygems_mfa_required: 'true'
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: 3.0.0
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ requirements: []
58
+ rubygems_version: 3.6.7
59
+ specification_version: 4
60
+ summary: Ruby SDK for TikTok Open API - OAuth authentication and API client
61
+ test_files: []