I'm trying to integrate the TikTok API into my application using the PKCE (Proof Key for Code Exchange) flow for OAuth 2.0. Despite following the documentation and ensuring that the code_verifier
and code_challenge
are generated and passed correctly, I keep receiving the error:
{
"error": "invalid_request",
"error_description": "Code verifier or code challenge is invalid.",
"log_id": "..."
}
Here's a summary of my implementation:
code_verifier
and code_challenge
:
code_verifier
is a high-entropy random string of 64 characters.code_challenge
is the base64-url-encoded SHA-256 hash of the code_verifier
.import secrets
import hashlib
import base64
import requests
from flask import Flask, request, redirect, session
import re
import urllib.parse
app = Flask(__name__)
app.secret_key = secrets.token_urlsafe(64)
client_key = 'your_client_key'
client_secret = 'your_client_secret'
redirect_uri = 'http://127.0.0.1:5000/callback/'
scopes = 'video.upload'
def generate_random_string(length):
characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~'
return ''.join(secrets.choice(characters) for _ in range(length))
def generate_code_challenge_pair():
code_verifier = generate_random_string(64) # Generate a code_verifier with 64 characters
sha256_hash = hashlib.sha256(code_verifier.encode('utf-8')).digest()
code_challenge = base64.urlsafe_b64encode(sha256_hash).decode('utf-8').rstrip('=')
return code_verifier, code_challenge
@app.route('/')
def home():
code_verifier, code_challenge = generate_code_challenge_pair()
state = generate_random_string(16)
session['code_verifier'] = code_verifier
session['state'] = state
tiktok_auth_url = (
f'https://www.tiktok.com/v2/auth/authorize/?'
f'client_key={client_key}&scope={scopes}&response_type=code&'
f'redirect_uri={redirect_uri}&state={state}&'
f'code_challenge={code_challenge}&code_challenge_method=S256'
)
return redirect(tiktok_auth_url)
@app.route('/callback/')
def callback():
code = request.args.get('code')
state = request.args.get('state')
if state != session.get('state'):
return 'CSRF verification failed', 400
code_verifier = session.get('code_verifier')
if not code_verifier:
return 'Missing code verifier', 400
decoded_code = urllib.parse.unquote(code)
access_token = get_access_token(decoded_code, code_verifier)
if access_token:
return f'Authentication successful! Access token: {access_token}'
else:
return 'Failed to obtain access token', 400
def get_access_token(code, code_verifier):
url = 'https://open.tiktokapis.com/v2/oauth/token/'
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
payload = {
'client_key': client_key,
'client_secret': client_secret,
'code': code,
'grant_type': 'authorization_code',
'redirect_uri': redirect_uri,
'code_verifier': code_verifier
}
response = requests.post(url, headers=headers, data=payload)
data = response.json()
if 'access_token' in data:
return data['access_token']
return None
if __name__ == '__main__':
app.run(port=5000, debug=True)
Redirecting to TikTok for authorization:
code_challenge
and state
.Handling the callback:
code_verifier
is then used to request an access token.Despite this setup, the response from TikTok's token endpoint consistently states that the "Code verifier or code challenge is invalid."
I've double-checked the generation and passing of both the code_verifier
and code_challenge
. Here are some example values for reference:
WBwqf0e8J5NKZukn
okYXNycnagbXKg4Alkum9JPnGI-WJsnxENO3NCCHHxVilhKE_XzPHhKnBjgprrMtBai2vQrDu2YIYjm3nzgZv4HgCB4nxffI0zm36W69d5jDpGsh_gfmjR9CG6RG4saRDuFeTTIr0IYnx7fDFNhiAv1KkYorssycwM4VbBNEr_FJUtBiyv7Cw_WU9EylNoa5Vl6H2jFCw4poIMsUwE7JSBm7OgM4DzceqfS5z7_yAP14pOWaT3GHqd0jALys0LNX*1!4549.va
Q6TYgUOmuBlhmw1IgAVSPJQ4t14sf.CdD4f3.ZR2ZLpCumYzIkMD4b7-DFwoffCs
{'client_key': 'sbaw7maxtihzttrwqu', 'client_secret': 'T1J1o0JwyZf3ZehwRqiTnfs7JvRFUYk3', 'code': 'okYXNycnagbXKg4Alkum9JPnGI-WJsnxENO3NCCHHxVilhKE_XzPHhKnBjgprrMtBai2vQrDu2YIYjm3nzgZv4HgCB4nxffI0zm36W69d5jDpGsh_gfmjR9CG6RG4saRDuFeTTIr0IYnx7fDFNhiAv1KkYorssycwM4VbBNEr_FJUtBiyv7Cw_WU9EylNoa5Vl6H2jFCw4poIMsUwE7JSBm7OgM4DzceqfS5z7_yAP14pOWaT3GHqd0jALys0LNX*1!4549.va', 'grant_type': 'authorization_code', 'redirect_uri': 'http://127.0.0.1:5000/callback/', 'code_verifier': 'Q6TYgUOmuBlhmw1IgAVSPJQ4t14sf.CdD4f3.ZR2ZLpCumYzIkMD4b7-DFwoffCs'}
Does anyone have experience with TikTok's PKCE implementation or see where I might be going wrong? Any help would be greatly appreciated!
As suggested by user Patola, the issue was that the SHA-256 hash needed to be converted to a hex string after the hash was created. The correct function for generating the code_verifier
and code_challenge
pair should look like this:
def generate_code_challenge_pair():
code_verifier = generate_random_string(60)
sha256_hash = hashlib.sha256(code_verifier.encode('utf-8')).digest()
code_challenge = sha256_hash.hex() # Convert to hex string
return code_verifier, code_challenge
After making this adjustment, the API no longer returns the "Code verifier or code challenge is invalid" error.