arlo
arlo copied to clipboard
403 Client Error: Forbidden for url: https://ocapi-app.arlo.com/api/auth
Is anyone else seeing this 403 Client Error?
I started to see it on May 09, my script runs automated
so I didn't actually notice this issue in my logs
until last week.
I thought maybe it was an MFA issue,
so I've tried to add MFA as explained in the wiki,
but I cant even get past the 403 error.
What version of Python are you using (python -V
)?
Python 3.10.4
What operating system and processor architecture are you using (python -c 'import platform; print(platform.uname());'
)?
('Darwin', 'MacPro-Mojave.local', '18.7.0', 'Darwin Kernel Version 18.7.0: Tue Jun 22 19:37:08 PDT 2021; root:xnu-4903.278.70~1/RELEASE_X86_64', 'x86_64', 'i386')
Which Python packages do you have installed (run the pip freeze
or pip3 freeze
command and paste output)?
arlo==1.2.59 (also test with .64 version)
cachetools==5.3.1
certifi==2023.5.7
cffi==1.15.0
charset-normalizer==3.1.0
click==8.1.3
cloudscraper==1.2.60
cryptography==37.0.2
google-api-core==2.11.1
google-api-python-client==2.90.0
google-auth==2.21.0
google-auth-httplib2==0.1.0
google-auth-oauthlib==1.0.0
googleapis-common-protos==1.59.1
httplib2==0.22.0
idna==3.4
monotonic==1.6
oauthlib==3.2.2
paho-mqtt==1.6.1
pickle-mixin==1.0.2
protobuf==4.23.3
pyaarlo @ git+https://github.com/twrecked/pyaarlo@2d6941dc903fe2fca01ac9d82fe708d1299ebe81
pyasn1==0.5.0
pyasn1-modules==0.3.0
pycparser==2.21
pycryptodome==3.14.1
pyparsing==3.1.0
PySocks==1.7.1
PyYAML==6.0
requests==2.31.0
requests-oauthlib==1.3.1
requests-toolbelt==0.9.1
rsa==4.9
six==1.16.0
sseclient==0.0.22
Unidecode==1.3.4
uritemplate==4.1.1
urllib3==1.24
Which version of ffmpeg are you using (ffmpeg -version
)?
ffmpeg version 1.2-tessus Copyright (c) 2000-2013 the FFmpeg developers
built on Mar 15 2013 01:18:55 with llvm-gcc 4.2.1 (LLVM build 2336.1.00)
configuration: --prefix=/Users/tessus/data/ext/ffmpeg/sw --as=yasm --extra-version=tessus --disable-shared --enable-static --disable-ffplay --enable-gpl --enable-pthreads --enable-postproc --enable-libmp3lame --enable-libtheora --enable-libvorbis --enable-libx264 --enable-libxvid --enable-libspeex --enable-bzlib --enable-zlib --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libxavs --enable-version3 --enable-libvo-aacenc --enable-libvo-amrwbenc --enable-libvpx --enable-libgsm --enable-libopus --enable-fontconfig --enable-libfreetype --enable-libass --enable-filters --enable-runtime-cpudetect
libavutil 52. 18.100 / 52. 18.100
libavcodec 54. 92.100 / 54. 92.100
libavformat 54. 63.104 / 54. 63.104
libavdevice 54. 3.103 / 54. 3.103
libavfilter 3. 42.103 / 3. 42.103
libswscale 2. 2.100 / 2. 2.100
libswresample 0. 17.102 / 0. 17.102
libpostproc 52. 2.100 / 52. 2.100
Which Arlo hardware do you have (camera types - [Arlo, Pro, Q, etc.], basestation model, etc.)?
not relevant
What did you do?
This code was working for me up without MFA until May 09 2023 - I thought maybe it was an MFA issue, so I added MFA to the code, but still getting the same errrors.
from arlo import Arlo
from datetime import timedelta, date, datetime
import logging
# from pathlib import Path
import config
import check_subdirs as chksub
config = config.get_config()
USERNAME = config['creds']['username']
PASSWORD = config['creds']['password']
MFA = config['creds']['mfa']
logger = logging.getLogger(__name__)
ROOTPATH = config['paths']['root_path']
def download_mp4s():
"""
Iterate over the videos in the arlo S3 bucket, compare against videos stored locally, dowload
all new files, rename downloaded files with a datetime, skip those that have already been downloaded.
"""
# Instantiating the Arlo object automatically calls Login(), which returns an oAuth token that gets cached.
# Subsequent successful calls to login will update the oAuth token.
try:
arlo = Arlo(USERNAME, PASSWORD, MFA)
logger.info("Successfully logged into Arlo account")
today = (date.today()-timedelta(days=0)).strftime("%Y%m%d")
start_date = (date.today()-timedelta(days=30)).strftime("%Y%m%d")
# Get all of the recordings for a date range.
library = arlo.GetLibrary(start_date, today)
logger.info("Connected to the Arlo Library")
devices = arlo.GetDevices()
# print(devices)
device_list = []
for device in devices:
deviceId = device["deviceId"]
deviceName = device["deviceName"]
device_dict = {device["deviceId"]: device["deviceName"]}
device_list.append(device_dict)
logger.info(f"Devices found in library: {device_list}")
# Iterate through the recordings in the library.
download_count = 0
for recording in library:
deviceId = recording["deviceId"]
deviceNum = next(i for i,d in enumerate(device_list) if deviceId in d)
deviceName = device_list[deviceNum][deviceId]
videofilename = datetime.fromtimestamp(int(recording['name'])//1000).strftime('%Y-%m-%d_%H-%M-%S') + '_' + recording['uniqueId'] + '.mp4'
###################
# The videos produced by Arlo are pretty small, even in their longest, best quality settings,
# but you should probably prefer the chunked stream (see below).
##################
# # Download the whole video into memory as a single chunk.
# video = arlo.GetRecording(recording['presignedContentUrl'])
# with open('videos/'+videofilename, 'wb') as f:
# f.write(video)
# f.close()
################33
root_dir = (ROOTPATH + deviceName + '/')
mp4_path = chksub.check_subdirs(root_dir, deviceName, videofilename)
if mp4_path.is_file() is not True:
stream = arlo.StreamRecording(recording['presignedContentUrl'])
with open(str(mp4_path), 'wb') as f:
for chunk in stream:
f.write(chunk)
f.close()
download_msg = 'Downloaded '+ videofilename+' from '+ recording['createdDate']+'.'
dowload_path_msg = "Download path: " + str(mp4_path)
download_count += 1
logger.info(download_msg)
logger.info(dowload_path_msg)
else:
# Get video as a chunked stream; this function returns a generator.
skip_msg = "Skipping: " + str(videofilename)
logger.debug(skip_msg)
continue
# Delete all of the videos you just downloaded from the Arlo library.
# Notice that you can pass the "library" object we got back from the GetLibrary() call.
# result = arlo.BatchDeleteRecordings(library)
if download_count != 0:
logger.info(f"Total videos downloaded: {download_count}")
else:
logger.info(f"No new videos for download.")
return
except Exception as e:
logger.exception(e)
if __name__ == '__main__':
download_mp4s()
What did you expect to see?
I use the code listed above to download a local copy of my arlo videos.
What did you see instead?
================================================================
ARLO Download Script - Start
Wednesday, 28. June 2023 09:46PM
================================================================
2023-06-28 21:46:34,815 | ERROR | Function: download_mp4s() | Line 103 | 403 Client Error: Forbidden for url: https://ocapi-app.arlo.com/api/auth
Traceback (most recent call last):
File "/Users/myname/_Github/ARLO-S3-Download/arlo_download.py", line 27, in download_mp4s
arlo = Arlo(USERNAME, PASSWORD, MFA)
File "/Users/myname/_Github/ARLO-S3-Download/.venv/lib/python3.10/site-packages/arlo.py", line 69, in __init__
self.LoginMFA(username, password, google_credential_file)
File "/Users/myname/_Github/ARLO-S3-Download/.venv/lib/python3.10/site-packages/arlo.py", line 201, in LoginMFA
auth_body = self.request.post(
File "/Users/myname/_Github/ARLO-S3-Download/.venv/lib/python3.10/site-packages/request.py", line 80, in post
return self._request(url, 'POST', params=params, headers=headers, raw=raw)
File "/Users/myname/_Github/ARLO-S3-Download/.venv/lib/python3.10/site-packages/request.py", line 56, in _request
r.raise_for_status()
File "/Users/myname/_Github/ARLO-S3-Download/.venv/lib/python3.10/site-packages/requests/models.py", line 1021, in raise_for_status
raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 403 Client Error: Forbidden for url: https://ocapi-app.arlo.com/api/auth
2023-06-28 21:46:34,820 | INFO | Function: main() | Line 89 |
================================================================
ARLO Download - Complete
Wednesday, 28. June 2023 09:46PM
================================================================
Does this issue reproduce with the latest release?
yes. same results. in .59 and .64, ive tried connecting through a VPN to see if I my IP was being blocked, i can also confirm that I have tried multiple user accounts - in each case I can log in just fine through the arlo web portal, but get the 403 when using the Arlo code.