Home >Backend Development >Python Tutorial >How to Redirect with Cookies and Headers Between Domains in HTTP?

How to Redirect with Cookies and Headers Between Domains in HTTP?

Mary-Kate Olsen
Mary-Kate OlsenOriginal
2024-11-02 18:30:02524browse

How to Redirect with Cookies and Headers Between Domains in HTTP?

Redirecting from One Domain to Another and Setting Cookies or Headers for the Other Domain

The Challenge

Redirection from one domain to another with custom headers or cookies set in the response is not possible due to HTTP protocol limitations. A redirection essentially consists of a header (Location) associated with the response, and it does not allow for any headers to be added to the target location.

Setting cookies for a different domain is also not allowed as it would pose a significant security risk. Browsers store cookies sent by the server with a response using the Set-Cookie header, and later send them back to the server for requests made to the same server within the same domain. Cookies are not sent to a different domain.

Solution 1: Redirect with Query Parameter and Cookie Setting on Target Domain

One approach is to have the source domain redirect the user to the target domain with an access token passed as a query parameter. The target domain can then read the token and set its own cookie, which the browser will store and send for subsequent requests.

Source Domain (appA.py)

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

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)
    return response</code>

Target Domain (appB.py)

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

app = FastAPI()

@app.get('/', response_class=HTMLResponse)
def home():
    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</code>

Solution 2: Cross-Origin Communication with Window.postMessage()

Another approach involves using Window.postMessage() for cross-origin communication. The source domain sends the token to the target domain, which stores it in localStorage and sets a cookie. Disadvantages include browser compatibility and the storage of sensitive data in localStorage.

Solution 3: StackExchange Universal Login Approach

A more robust solution is used by StackExchange for auto-login between its different sites. It involves sending an authentication token via an image's src attribute, which triggers a server response and sets cookies on the target site.

This requires browser acceptance of third-party cookies and CORS configuration on the target server. It also sends the token in the query string, posing potential security risks.

Source Domain (appA.py)

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

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>
          <input type="button" value="Submit" onclick="submit()">
          <script>
             function submit() {
                fetch('/submit', {
                     method: 'POST',
                  })
                  .then(res => {
                     authHeader = res.headers.get('Authorization');
                     if (authHeader.startsWith(&quot;Bearer &quot;))
                        token = authHeader.substring(7, authHeader.length);
                     return res.text();
                  })
                  .then(data => {
                     var url = 'http://example.test:8001/submit?token=' + encodeURIComponent(token);
                     var img = document.createElement('img');
                     img.style = 'display:none';
                     img.crossOrigin = 'use-credentials';
                     img.onerror = function(){
                        window.location.href = 'http://example.test:8001/';
                     }
                     img.src = url;
                  })
                  .catch(error => {
                     console.error(error);
                  });
             }
          </script>
       </body>
    </html>
    '''

@app.post('/submit')
def submit():
    token = 'MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3'
    headers = {'Authorization': f'Bearer {token}'}
    response = Response('success', headers=headers)
    response.set_cookie(key='access-token', value=token, httponly=True)
    return response</code>

Target Domain (appB.py)

<code class="python">from fastapi import FastAPI, Request, Response
from fastapi.responses import RedirectResponse
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

origins = ['http://localhost:8000', 'http://127.0.0.1:8000',
           'https://localhost:8000', 'https://127.0.0.1:8000'] 

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=[&quot;*&quot;],
    allow_headers=[&quot;*&quot;],
)

@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.get('/submit')
def submit(request: Request, token: str):
    response = Response('success')
    response.set_cookie(key='access-token', value=token, samesite='none', secure=True, httponly=True) 
    return response</code>

Security Considerations

When transferring tokens or setting cookies between domains, it is crucial to consider security implications. Avoid sending sensitive data in the query string as it can be intercepted or compromised. Use HTTPS connections for secure data transfer. Set the SameSite flag to 'None' with the Secure flag for cross-site access protection.

The above is the detailed content of How to Redirect with Cookies and Headers Between Domains in HTTP?. 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