I have a Python/Bottle server application, a Seaweed media server, and an NGINX web server.
I need to check the client's permission before allowing shim to download a file.
So:
User requests to download a file.
Backend checks user permission. If granted, redirects it to the file location.
But the problem is that the Seaweed secured by JWT and an Authorization header must be set.
Can I set Authorization header and then redirect user?
Yes, you can set headers on redirects. Here's one way to do it in Bottle:
#route(...)
def handler():
# after you've authorized the user, set your auth header:
response.set_header('Your-auth-header', auth_token)
# perform the redirect
response.status = 302
response.body = ''
response.set_header('Location', file_location)
raise response
(That's off the top of my head; not tested code.)
Related
I wonder if there is a way to authenticate each redirected URL when working with Python modules such as httpx or requests?
Problem Statement
I am trying to connect to an API endpoint under the company network. Due to the company's cyber security measures, the API endpoint will be randomly masked with a company proxy, which causes the 307 Redirect status code.
my current code snippet looks like the below:
import httpx
api_url = 'https://demo.vizionapi.com/carriers'
head = {
'X-API-Key':'API KEY'
}
response = httpx.get(url=api_url, verify='supporting_files/cacert.pem',
headers=head, auth=('my username', 'my password'),
follow_redirects=True)
With above code, I received the 401 authentication needed error (But auth has been passed). This error will only happen when redirection occurs due to the company proxy.
Question:
My assumption is the authentication is only being passed into the first URL not the redirected URL. Therefore, I wonder if anyone know how I can use the same auth parameter for all URLs (direct & redirect)?
Any suggestion will be deeply appracaited.
I don't know what requests behavior with regards to auth during redirect is, but the first solution to come to mind is to manually follow the redirects yourself. Put your request in a loop that checks for the 3xx response codes, and handle auth however you want to.
I have been struggling with this problem for two weeks, Basically I have configured the auth0 settings with my Flask app which runs on local host.
So, I have the following two endpoints in my flask app:
A public endpoint which requires no authentication process:
#APP.route("/api/public")
#cross_origin(headers=["Content-Type", "Authorization"])
def public():
# No access token required to access this route
response = "Hello from a public endpoint! You don't need to be authenticated to see this."
return jsonify(message=response)
A private endpoint which requires authentication:
#APP.route("/api/private")
#cross_origin(headers=["Content-Type", "Authorization"])
#cross_origin(headers=["Access-Control-Allow-Origin", "http://localhost:3000"])
#requires_auth
def private():
# A valid access token is required to access this route
response = "Hello from a private endpoint! You need to be authenticated to see this."
return jsonify(message=response)
So here is the following scenario:
I try to log in with the auth0 url that redirects me to universal login page for my app. After successful login, it redirects me to the private end point and I get 401 Un-authorized error.
Whenever I make this request with valid token from the browser it throws 401 error.
With the same token, I call this endpoint using postman it works !!
The reason for that is this request from the browser is not including the Authorization header, unlike postman.
I really don't understand why the browser is not including the Authorization header.
Can someone explains ?
NOTE: At first it was working using browser without any problems but suddenly it appeared somehow.
Since the private endpoint requires authentication, whenever I try to access the private end point this function is called:
def get_token_auth_header():
"""Obtains the access token from the Authorization Header
"""
auth = request.headers.get("Authorization", None) # HERE IS THE PROBLEM OCCURRS
print("REQUEST HEADERS: \n", request.headers)
if not auth:
raise AuthError({"code": "authorization_header_missing",
"description":
"Authorization header is expected"}, 401)
parts = auth.split()
if parts[0].lower() != "bearer":
raise AuthError({"code": "invalid_header",
"description":
"Authorization header must start with"
" Bearer"}, 401)
elif len(parts) == 1:
raise AuthError({"code": "invalid_header",
"description": "Token not found"}, 401)
elif len(parts) > 2:
raise AuthError({"code": "invalid_header",
"description":
"Authorization header must be"
" Bearer token"}, 401)
token = parts[1]
return token
I have been struggling with this for almost two weeks, I tried everything.
I would really appreciate your help.
I'm copying here the same answer I provided in the community forum in case you still need it ;)
It seems you are missing the authlib configuration ;)
You can see here how to configure that and use it on your app
I am trying to setup token based authentication in python. using Django/DRF. but this is more about http in general i think.
When users put in username/password I return to them their token via JSON.
The client then can post the token in HTTP Header for me to check.
My problem is I want the token to persist in the header automatically, just like cookies.
When the server says "set-cookie" to browser (Chrome/FF), the browser will automatically send up the cookie without me actually doing anything. Is there something I can do with this token?
I have tried storing it in header: "Authorization", but the browser didn't return it. Is there something like "Set-Authorization"?
thanks
No, only cookies stored in browser persistently. All other headers are transient by HTTP protocol definition.
I have a Tornado app which uses Google Oauth 2.0 Authentication, gets the email and sets that in a cookie. Now I don't want anyone else to access this cookie, copy the value and get another user's details on my app. So I want to make this cookie httponly and secure cookie. However when I pass these as arguments its not able to set the cookie:
self.set_secure_cookie('trakr', email, secure=True, httponly=True)
I am suing Tornado 3.2.2 and Python 2.7.5.
since its not able to set the cookie, it keeps redirecting to google auth page. Here is my code:
class GAuthLoginHandler(BaseHandler, tornado.auth.GoogleOAuth2Mixin):
#tornado.gen.coroutine
def get(self):
if self.get_current_user():
self.redirect('/products')
return
if self.get_argument('code', False):
user = yield self.get_authenticated_user(redirect_uri=settings.google_redirect_url,
code=self.get_argument('code'))
if not user:
self.clear_all_cookies()
raise tornado.web.HTTPError(500, 'Google authentication failed')
access_token = str(user['access_token'])
http_client = self.get_auth_http_client()
response = yield http_client.fetch('https://www.googleapis.com/oauth2/v1/userinfo?access_token='+access_token)
user = json.loads(response.body)
self.set_secure_cookie('trakr', user['email'], secure=True, httponly=True)
self.redirect(self.get_argument("next", "/products"))
return
elif self.get_secure_cookie('trakr'):
self.redirect('/products')
return
else:
yield self.authorize_redirect(
redirect_uri=settings.google_redirect_url,
client_id=self.settings['google_oauth']['key'],
scope=['email'],
response_type='code',
extra_params={'approval_prompt': 'auto'})
The code works perfectly fine when I remove secure and httponly arguments. It also works if I just send httponly argument, however it doesn't seem to set the cookie when I pass both the arguments.
Am I doing something wrong?
The issue is not with Tornado or Python, but with my server as I was not using HTTPS:
A secure cookie has the secure attribute enabled and is only used via
HTTPS, ensuring that the cookie is always encrypted when transmitting
from client to server. This makes the cookie less likely to be exposed
to cookie theft via eavesdropping. In addition to that, all cookies
are subject to browser's same-origin policy.
I am trying to authenticate an application with the API.
Here's How:
I am opening a URL using webbrowser.open.
The user authenticates the application, and is redirected to another URL, which is
https://stackexchange.com/oauth/login_successwith arguments encoded with this URL.
A sample redirect url is:
.../login_success#access_token=xyz&expires=00000
My Current code:
auth_url = 'https://stackexchange.com/oauth/dialog'
def authenticate():
scope = "write_access,private_info,read_inbox"
url = make_url(auth_url,client_id=132,
scope=scope,response_type='code',
redirect_uri='https://stackexchange.com/oauth/login_success')
webbrowser.open(url)
How can I get the redirect URL (the URL the user is taken to) after the user authenticates themselves???
Try to fire up your own little HTTP server for just one request, let the API redirect to it and wait for the redirected request to appear. This is not a complete example, just the basic concept:
import BaseHTTPServer
auth_url = 'https://stackexchange.com/oauth/dialog'
# replace with your own http handlers
def wait_for_request(server_class=BaseHTTPServer.HTTPServer,
handler_class=BaseHTTPServer.BaseHTTPRequestHandler):
server_address = ('', 8000)
httpd = server_class(server_address, handler_class)
return httpd.handle_request()
def authenticate():
scope = "write_access,private_info,read_inbox"
url = make_url(auth_url,client_id=132,
scope=scope,response_type='code',
redirect_uri='http://localhost:8000/login_success')
webbrowser.open(url)
wait_for_request()
You probably need to use HTTPS though. In the long run, you might be better off with an existing OAuth implementation.
After the user authenticates with stack exchange, the SE page will redirect back to your page ("redirect_uri" below). Your code currently redirects to https://stackexchange.com/oauth/login_success ; instead, you should redirect to a page you control.
Open a new window at https://stackexchange.com/oauth/dialog, with these query string parameters
client_id
scope
redirect_uri
state - optional
The user approves your app
The user is redirected to redirect_uri, with these parameters in the hash
access_token
expires - optional, only if scope doesn't contain no_expiry
source: https://api.stackexchange.com/docs/authentication