Getting 503 code when login
vibalcam opened this issue · comments
Same issue. I am being redirected to http://127.0.0.1:8080/?error=access_denied&error_description=User%20denied%20access&state=None
@lazeroffmichael also experiencing this issue..
@vibalcam & @eduardocopat did either of you figure out a temporary workaround?
@vibalcam @broskees @eduardocopat
For some reason, I am not able to reproduce the error. Would you guys be able to provide some more information such as the ticktick-py version you are using, python version, and which request it is failing at.
My error comes when doing the http_post or http_get methods in api.py. I found a workaround by logging into the website and using Postman to recreate the interaction. I found out that when including the following headers, it all worked fine:
HEADERS = {
'authority': 'api.ticktick.com',
'sec-ch-ua': '" Not;A Brand";v="99", "Google Chrome";v="97", "Chromium";v="97"',
'x-device': '{...}',
'x-requested-with': 'XMLHttpRequest',
'sec-ch-ua-mobile': '?0',
'content-type': 'application/json',
'user-agent': '...',
'sec-ch-ua-platform': '"Windows"',
'accept': '*/*',
'origin': 'https://ticktick.com',
'sec-fetch-site': 'same-site',
'sec-fetch-mode': 'cors',
'sec-fetch-dest': 'empty',
'referer': 'https://ticktick.com/',
'accept-language': 'es,en-US;q=0.9,en;q=0.8',
}
Thus, the http_post method would end up being:
def http_post(self, url, **kwargs):
"""
Sends an http post request with the specified url and keyword arguments.
Arguments:
url (str): Url to send the request.
**kwargs: Arguments to send with the request.
Returns:
dict: The json parsed response if possible or just a string of the response text if not.
Raises:
RunTimeError: If the request could not be completed.
"""
if 'headers' not in kwargs:
response = self._session.post(url, headers=self.HEADERS, **kwargs)
else:
kwargs['headers'].update(self.HEADERS)
response = self._session.post(url, **kwargs)
self.check_status_code(response, 'Could Not Complete Request')
try:
return response.json()
except ValueError:
return response.text
Same for http_get and everything works fine.
@vibalcam @broskees @eduardocopat
For some reason, I am not able to reproduce the error. Would you guys be able to provide some more information such as the ticktick-py version you are using, python version, and which request it is failing at.
Hello, @lazeroffmichael! First, thanks for this library :).
This is what I have installed:
Python 3.10.2
Package Version
------------------ ---------
certifi 2021.10.8
charset-normalizer 2.0.11
idna 3.3
pip 21.2.4
pytz 2021.1
regex 2021.4.4
requests 2.26.0
setuptools 58.1.0
ticktick-py 2.0.2
urllib3 1.26.7
wheel 0.37.1
I am executing the code in a new PC (thus, I don't have the OAuth file). This is my simple script:
import os
import sys
import json
from ticktick.oauth2 import OAuth2 # OAuth2 Manager
from ticktick.api import TickTickClient # Main Interface
# using get will return `None` if a key is not present rather than raise a `KeyError`
#print())
client = os.environ.get('TICKTICK_CLIENT_ID')
secret = os.environ.get('TICKTICK_CLIENT_SECRET')
import requests
requests_session = requests.session()
auth_client = OAuth2(client_id=client,
client_secret=secret,
redirect_uri='http://127.0.0.1:8080',
session=requests_session)
client = TickTickClient('xxxxx@gmail.com', os.environ.get('TICKTICK_PWD'), auth_client)
#print('fin')
#print()
f = open("tasks.txt", "w")
tasks = client.state['tasks']
f.write(json.dumps(tasks))
f.close()
sys.stdout.flush()
When I run the app, I am redirected to the following page:
Then I click allow and I'm redirected to this page:
http://127.0.0.1:8080/?error=access_denied&error_description=User%20denied%20access&state=None
Could it be something with the TickTick API? I'll try vibalcam suggestion above, maybe try to create another "app" at the TickTick API
@vibalcam @eduardocopat @lazeroffmichael
I haven't debugged too deeply, but I'm also getting the error with a simple script:
from toml import load
from ticktick.oauth2 import OAuth2
from ticktick.api import TickTickClient
config = load('config.toml')
auth_client = OAuth2(
client_id = config["connections"]["ticktick"]["ticktick_client_id"],
client_secret = config["connections"]["ticktick"]["ticktick_client_secret"],
redirect_uri = config["connections"]["ticktick"]["ticktick_redirect_uri"]
)
tt = TickTickClient(
username = config["connections"]["ticktick"]["ticktick_user"],
password = config["connections"]["ticktick"]["ticktick_pass"],
oauth = auth_client
)
name = 'Get Groceries' # Task Name
local_task = tt.task.builder(name) # Create a dictionary for the task
groceries = tt.task.create(local_task) # Actually create the task
and this is the traceback:
Traceback (most recent call last):
File "/Users/josephroberts/localdev/task-sync-db/test.py", line 21, in <module>
groceries = tt.task.create(local_task) # Actually create the task
File "/usr/local/lib/python3.9/site-packages/ticktick/managers/tasks.py", line 147, in create
response = self._client.http_post(url=url, json=task, headers=self.oauth_headers)
File "/usr/local/lib/python3.9/site-packages/ticktick/api.py", line 180, in http_post
self.check_status_code(response, 'Could Not Complete Request')
File "/usr/local/lib/python3.9/site-packages/ticktick/api.py", line 117, in check_status_code
raise RuntimeError(error_message)
RuntimeError: Could Not Complete Request
When I pprint
the post requests by editing the api.py
http_post()
function:
- I get one with a 200 response and just json of my account details.
- Then the second response is a 401 response like so (I replaced the access token in the output I pasted here):
{'error': 'invalid_token',
'error_description': 'Invalid access token: '
'MYACCESSTOKEN',
'errors': [{'message': 'Invalid access token: '
'MYACCESSTOKEN'}]}
My error comes when doing the http_post or http_get methods in api.py. I found a workaround by logging into the website and using Postman to recreate the interaction. I found out that when including the following headers, it all worked fine:
HEADERS = { 'authority': 'api.ticktick.com', 'sec-ch-ua': '" Not;A Brand";v="99", "Google Chrome";v="97", "Chromium";v="97"', 'x-device': '{...}', 'x-requested-with': 'XMLHttpRequest', 'sec-ch-ua-mobile': '?0', 'content-type': 'application/json', 'user-agent': '...', 'sec-ch-ua-platform': '"Windows"', 'accept': '*/*', 'origin': 'https://ticktick.com', 'sec-fetch-site': 'same-site', 'sec-fetch-mode': 'cors', 'sec-fetch-dest': 'empty', 'referer': 'https://ticktick.com/', 'accept-language': 'es,en-US;q=0.9,en;q=0.8', }
Thus, the http_post method would end up being:
def http_post(self, url, **kwargs): """ Sends an http post request with the specified url and keyword arguments. Arguments: url (str): Url to send the request. **kwargs: Arguments to send with the request. Returns: dict: The json parsed response if possible or just a string of the response text if not. Raises: RunTimeError: If the request could not be completed. """ if 'headers' not in kwargs: response = self._session.post(url, headers=self.HEADERS, **kwargs) else: kwargs['headers'].update(self.HEADERS) response = self._session.post(url, **kwargs) self.check_status_code(response, 'Could Not Complete Request') try: return response.json() except ValueError: return response.text
Same for http_get and everything works fine.
@vibalcam what did you place in the x-device
field?
I tried @vibalcam's solution, with a small differentiation in the HEADERS
constant, then printed out the response codes in http_get()
& http_post()
- same issue as before.
HEADERS
constant:
HEADERS = {
'authority': 'api.ticktick.com',
'sec-ch-ua': '" Not;A Brand";v="99", "Google Chrome";v="97", "Chromium";v="97"',
'x-device-user-agent': USER_AGENT,
'x-requested-with': 'XMLHttpRequest',
'sec-ch-ua-mobile': '?0',
'content-type': 'application/json',
'User-Agent': USER_AGENT,
'sec-ch-ua-platform': '"Windows"',
'accept': '*/*',
'origin': 'https://ticktick.com',
'sec-fetch-site': 'same-site',
'sec-fetch-mode': 'cors',
'sec-fetch-dest': 'empty',
'referer': 'https://ticktick.com/',
'accept-language': 'es,en-US;q=0.9,en;q=0.8'
}
Console Output:
<Response [200]>
<Response [200]>
<Response [200]>
<Response [401]>
Traceback (most recent call last):
File "/Users/josephroberts/localdev/task-sync-db/test.py", line 21, in <module>
groceries = tt.task.create(local_task) # Actually create the task
File "/usr/local/lib/python3.9/site-packages/ticktick/managers/tasks.py", line 147, in create
response = self._client.http_post(url=url, json=task, headers=self.oauth_headers)
File "/usr/local/lib/python3.9/site-packages/ticktick/api.py", line 206, in http_post
self.check_status_code(response, 'Could Not Complete Request')
File "/usr/local/lib/python3.9/site-packages/ticktick/api.py", line 135, in check_status_code
raise RuntimeError(error_message)
RuntimeError: Could Not Complete Request
Lol, I tried deleting the .token-oauth
file. @vibalcam's solution works now.
Unfortunately for me, @vibalcam solution did not work :(.
Unfortunately for me, @vibalcam solution did not work :(.
Try to follow the steps I took:
- Log into TickTick web and, using your browser's inspector, capture the http login request.
- Copy the headers to a app capable of doing API calls (I used PostMan). The easiest way I found was to export the http request login and import it into Postman.
- Test with Postman if it works
- Export the headers to Python
- Delete and regenerate TickTick's
.token-oauth
Unfortunately for me, @vibalcam solution did not work :(.
Try to follow the steps I took:
- Log into TickTick web and, using your browser's inspector, capture the http login request.
- Copy the headers to a app capable of doing API calls (I used PostMan). The easiest way I found was to export the http request login and import it into Postman.
- Test with Postman if it works
- Export the headers to Python
Appreciate the input on this. I have tried these steps but am still getting the similar access_denied response despite all attempted OAUTH2 variations on headers.
I have tried those headers and also my own from a successful authentication to the ticktick webapp:
HEADERS = {'authority':'api.ticktick.com',
'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36',
'x-requested-with':'XMLHttpRequest',
'x-device':'{...}',
'content-type':'application/json',
'accept':'/',
'sec-gpc':'1',
'origin':'https://ticktick.com',
'sec-fetch-site':'same-site',
'sec-fetch-mode':'cors',
'sec-fetch-dest':'empty',
'referer':'https://ticktick.com/'}
Noting but unsure of relevancy that I cannot achieve token generation even through manual request to the auth url through browser. Always returning access denied despite succesful POST request to confirm acceptance. And additionally, while in the documentation the access states are displayed to be accepted with an account image this does not appear correctly in all scenarios.
Wonder if you have any insight on other factors or code you changed to potentially successfully authenticate?
I forgot to mention that you have to regenerate .token-oauth
.
If it does not allow you to regenerate the token, make sure you the code in http_post and http_get to:
if 'headers' not in kwargs:
response = self._session.post(url, headers=self.HEADERS, **kwargs)
else:
kwargs['headers'].update(self.HEADERS)
response = self._session.post(url, **kwargs)
self.check_status_code(response, 'Could Not Complete Request')
try:
return response.json()
except ValueError:
return response.text
This just makes sure that no other headers were being used.
I forgot to mention that you have to regenerate
.token-oauth
.If it does not allow you to regenerate the token, make sure you the code in http_post and http_get to:
if 'headers' not in kwargs: response = self._session.post(url, headers=self.HEADERS, **kwargs) else: kwargs['headers'].update(self.HEADERS) response = self._session.post(url, **kwargs) self.check_status_code(response, 'Could Not Complete Request') try: return response.json() except ValueError: return response.text
This just makes sure that no other headers were being used.
Hmm, not to be requesting support but interestingly I have no .token-oauth file generated, including a message in STDOUT that "Cache could not be read at: .token-oauth" which I had assumed was standard behavior if no valid token had been generated in past. If not, my issues may be differing.
To note I also applied the code mentioned but again seem to be experiencing different behavior, when you authenticate in this manner, does the browser window correctly display the requested permissions and your username? As it does in the documentation but not for mine. Somehow suggesting my request may be malformed if this is the case.
EDIT: Not sure if can confirm but potentially my issue is different from that of @vibalcam but looks the same as @eduardocopat . In that no variation of the authentication URL produces a code which can be later used to generate the token. always that authentication error. Further debugging has shown that my issue is not seemingly with the HTTP_POST or GET code in the API.PY as these functions appear to be only used after the redirect through the browser (If my understanding is correct)? As such they are not typically seeming to be run in my case as the initial authentication fails. Interestingly, this is also the case for me on the Zapier and IFTTT integrations (not sure if these work for others) which would somehow suggest a device or account issue, despite trying variations of differing situations of both.
EDIT 2: It now appears to be working pending further testing at 1/3/2022. It is most likely considering these circumstances that this was some sort of strange account bug, or likely I sent a few failed authentication requests and it resulted in an IP ban on the server side. I am happy to delete my comments on this issue if the author prefers or can leave here incase somebody else encounters this and mistakes it as relevant to the bug.
Cache could not be read at: .token-oauth
Enter the URL you were redirected to: http://127.0.0.1:8080/?code=BANANA&state=None
Traceback (most recent call last):
File "/Users/dkvdm/Projects/portfolio/test.py", line 4, in <module>
auth_client = OAuth2(client_id="BANANANANANA",
File "/Users/dkvdm/.virtualenvs/portfolio/lib/python3.9/site-packages/ticktick/oauth2.py", line 136, in __init__
self.get_access_token(check_cache=check_cache, check_env=env_key)
File "/Users/dkvdm/.virtualenvs/portfolio/lib/python3.9/site-packages/ticktick/oauth2.py", line 311, in get_access_token
token_info = self._request_access_token()
File "/Users/dkvdm/.virtualenvs/portfolio/lib/python3.9/site-packages/ticktick/oauth2.py", line 225, in _request_access_token
token_info = self._post(self.OBTAIN_TOKEN_URL, params=payload)
File "/Users/dkvdm/.virtualenvs/portfolio/lib/python3.9/site-packages/ticktick/oauth2.py", line 249, in _post
raise RuntimeError("POST request could not be completed")
RuntimeError: POST request could not be completed
This is still causing issues for me, anybody else experiencing similar login issues?
Cache could not be read at: .token-oauth Enter the URL you were redirected to: http://127.0.0.1:8080/?code=BANANA&state=None Traceback (most recent call last): File "/Users/dkvdm/Projects/portfolio/test.py", line 4, in <module> auth_client = OAuth2(client_id="BANANANANANA", File "/Users/dkvdm/.virtualenvs/portfolio/lib/python3.9/site-packages/ticktick/oauth2.py", line 136, in __init__ self.get_access_token(check_cache=check_cache, check_env=env_key) File "/Users/dkvdm/.virtualenvs/portfolio/lib/python3.9/site-packages/ticktick/oauth2.py", line 311, in get_access_token token_info = self._request_access_token() File "/Users/dkvdm/.virtualenvs/portfolio/lib/python3.9/site-packages/ticktick/oauth2.py", line 225, in _request_access_token token_info = self._post(self.OBTAIN_TOKEN_URL, params=payload) File "/Users/dkvdm/.virtualenvs/portfolio/lib/python3.9/site-packages/ticktick/oauth2.py", line 249, in _post raise RuntimeError("POST request could not be completed") RuntimeError: POST request could not be completedThis is still causing issues for me, anybody else experiencing similar login issues?
got the same POST request could not be completed
Error. Have you fix it ?