Home >Backend Development >Python Tutorial >How to Redirect Between Domains and Set Cookies or Headers?

How to Redirect Between Domains and Set Cookies or Headers?

DDD
DDDOriginal
2024-10-31 05:30:01392browse

How to Redirect Between Domains and Set Cookies or Headers?

How to redirect from one domain to another and set cookies or headers for the other domain?

As described here you cannot redirect to another domain with custom headers set, no matter what language or framework you use. A redirection in the HTTP protocol is basically a header (i.e., Location) associated with the response, and it doesn't allow for any headers to the target location to be added. When you add the Authorization header in your example, you basically set that header for the response which is instructing the browser to redirect, not for the redirect itself. In other words, you are sending that header back to the client.

As for the HTTP cookies, the browser stores the cookies sent by the server with the response (using the Set-Cookie header), and later sends the cookies with requests made to the same server inside a Cookie HTTP header. As per the documentation:

The Set-Cookie HTTP response header is used to send a cookie from the
server to the user agent, so that the user agent can send it back
to the server later. To send multiple cookies, multiple Set-Cookie
headers should be sent in the same response.

Hence, if this was a redirection from one app (with sub-domain, e.g., abc.example.test) to another (with sub-domain, e.g., xyz.example.test) that both have the same (parent) domain (and the domain flag was set to example.test when creating the cookies), cookies would be successfully shared between the two apps (as if domain is specified, then subdomains are always included). The browser will make a cookie available to the given domain including any sub-domains, no matter which protocol (HTTP/HTTPS) or port is used. You can limit a cookie's availability using the domain and path flags, as well as restrict access to the cookie with secure and httpOnly flags (see here and here, as well as Starlette documentation). If the httpOnly flag isn't set, a potential attacker can read and modify the information through JavaScript (JS), whereas a cookie with the httpOnly attribute is only sent to the server, and is inaccessible to JS on client side.

However, you cannot set cookies for a different domain. If this was permitted, it would present an enormous security flaw. Hence, since you are "trying to redirect the user from one application (domain) to another with some cookie set,...*"", it wouldn't work, as the cookie will only be sent with requests made to the same domain.

Solution 1

A solution, as described here, is to have domain (app) A redirecting the user to domain (app) B, with the access-token passed in the URL as a query parameter. Domain B would then read the token and set its own cookie, so that the browser will store and send that cookie with every subsequent request to domain B.

Please note that you should consider using a secure (HTTPS) communication, so that the token is transferred encrypted, as well as setting the secure flag when creating the cookie. Also, note that having the token in the query string poses a serious security risk, as sensitive data should never be passed in the query string. This is because the query string, which is part of the URL, appears in the address bar of the browser; thus, allowing the user to see and bookmark the URL with the token in it (meaning that it is saved on the disk). Also, the URL will make it to the browsing history, which means it will be written to the disk anyway and appear in the History tab (press Ctrl H to see the browser's history). Both the above would allow attackers (and people you share the computer/mobile device with) to steal such sensitive data. Additionally, many browser plugins/extensions track users' browsing activity—every URL you visit is sent to their servers for analysis, in order to detect malicious websites and warn you beforehand. Hence, you should take all the above into consideration before using the approach below (for related posts on this subject, see here, here and here).

To prevent displaying the URL in the address bar, the approach below uses a redirection within domain B as well. Once domain B receives the request to the /submit route with the token as a query parameter, domain B responds with a redirection to a bare URL with no tokens in it (i.e., its home page). Because of this redirection, the URL with the token in it wouldn't end up in the browsing history. Although this provides some protection against certain attacks described earlier, it doesn't mean that browser extensions, etc., won't still be able to capture the URL with the token in it.

If you are testing this on localhost, you need to give application B a different domain name; otherwise, as mentioned earlier, cookies will be shared between applications having the same domain, and hence, you would end up receiving the cookies set for domain A, and couldn't tell if the approach is working at all. To do that, you have to edit the /etc/hosts file (on Windows this is located in C:WindowsSystem32driversetc) and assign a hostname to 127.0.0.1. For example:

127.0.0.1 example.test

You shouldn't add the scheme or port to the domain, as well as shouldn't use common extensions, such as .com, .net, etc., otherwise it may conflict with accessing other websites on the Internet.

Once you access domain A below, you will need to click on the submit button to perform a POST request to the /submit route to start the redirection. The only reason for the POST request is because you are using it in your example and I am assuming you have to post some form-data. Otherwise, you could use a GET request as well. In app B, when performing a RedirectResponse from a POST route (i.e., /submit) to a GET route (i.e., /), the response status code changes to status.HTTP_303_SEE_OTHER, as described here, here and here. App A is listening on port 8000, while app B is listening on port 8001.

Run both apps below, and then access domain A at http://127.0.0.1:8000/.

appA.py

127.0.0.1 example.test

appB.py

<code class="python">from fastapi import FastAPI, FastAPI
from fastapi.responses import RedirectResponse, HTMLResponse
import uvicorn

app = FastAPI()
           
@app.get('/', response_class=HTMLResponse)
def home():
    return """"
    <!DOCTYPE html>
    <html>
       <body>
          <h2>Click the "submit" button to be redirected to domain B</h2>
          <form method="POST" action="/submit">
             <input type="submit" value="Submit">
          </form>
       </body>
    </html>
    """
        
@app.post("/submit")
def submit():
    token = 'MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3'
    redirect_url = f'http://example.test:8001/submit?token={token}'
    response = RedirectResponse(redirect_url)
    response.set_cookie(key='access-token', value=token, httponly=True)  # set cookie for domain A too
    return response
 
if __name__ == '__main__':
    uvicorn.run(app, host='0.0.0.0', port=8000)</code>

Solution 2

Another solution would be to use Window.postMessage(), which enables cross-origin communication between Window objects; for example, between a page and a pop-up that it spawned, or between a page and an iframe embedded within it. Examples on how to add event listeners and communicate between the windows can be found here. The steps to follow would be:

Step 1: Add to domain A a hidden iframe to domain B. For example:

<code class="python">from fastapi import FastAPI, Request, status
from fastapi.responses import RedirectResponse
import uvicorn

app = FastAPI()

@app.get('/')
def home(request: Request):
    token = request.cookies.get('access-token')
    print(token)
    return 'You have been successfully redirected to domain B!' \
           f' Your access token ends with: {token[-4:]}'
 
@app.post('/submit')
def submit(request: Request, token: str):
    redirect_url = request.url_for('home')
    response = RedirectResponse(redirect_url, status_code=status.HTTP_303_SEE_OTHER)
    response.set_cookie(key='access-token', value=token, httponly=True)
    return response
 
if __name__ == '__main__':
    uvicorn.run(app, host='0.0.0.0', port=8001)</code>

Step 2: As soon as you obtain the Authorization token from the

The above is the detailed content of How to Redirect Between Domains and Set Cookies or Headers?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn