The following command successfully downloads an artifact file from a GitHub workflow run: curl -L -H "Authorization: Bearer ghp_XXXX" -o arti.zip \ https://api.github.com/repos/OWNER/REPO/actions/artifacts/ID/zip The following Python code fails, with the same URL and authentication token: import os, urllib.request req = urllib.request.Request('https://api.github.com/repos/OWNER/REPO/actions/artifacts/ID/zip') req.add_header('Authorization', 'Bearer ghp_XXXX') with urllib.request.urlopen(req) as input: with open('arti.zip', 'wb') as output: output.write(input.read()) The Python exception is raised in urlopen(): urllib.error.HTTPError: HTTP Error 403: Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. What is wrong in the Python code? The request is redirected to another host and we can suspect that the authorization is not redirected as well. However, the Python doc for Request.add_header() says that "headers added using this method are also added to redirected requests". So it should work. The same code with any public URL and no authentication works. I have seen many over-complicated examples online and on SO, each one explaining that some other Python library should be used, etc. Isn't there a simple way to use urllib with a Bearer Authorization? Continue reading...