1

I have this client-server application that fetches an OAuth token from an external API. From the client, I call an endpoint to retrieve the auth URL, then I redirect the client to that URL such that a user can sign in and give permission to my application to use the external API. Then, the external API will redirect to the client with a code, that code is passed to my server which calls the external API to fetch an OAuth token and save it in a db.

To link a token to a user, I create a session_id in the /login endpoint

@app.get("/login")
async def login(request: Request, response: Response, db: Session = Depends(get_db)):
    params = {
        "client_id": CLIENT_ID,
        "scope": SCOPE,
        "code_challenge": create_code_challenge(app.state.verifier),
        "code_challenge_method": "S256",
        "response_type": "code",
    }
    res = requests.get(f"{AUTH_URL}", params=params)
    session_id = str(uuid.uuid4())
    response.set_cookie(key="session_id", value=session_id)
    return {"url": res.url}

And I share the session id as a cookie. In my /callback endpoint, which is called by the external API, I want to use this session_id in the token object that I'm saving in the db:

@app.get("/callback")
async def callback(code, request: Request, db: Session = Depends(get_db)) -> None:
    params = {
        "client_id": CLIENT_ID,
        "code": code,
        "code_verifier": app.state.verifier,
        "grant_type": "authorization_code",
    }
    headers = {"Content-Type": "application/x-www-form-urlencoded"}
    res = requests.post(
        TOKEN_URL,
        auth=HTTPBasicAuth(CLIENT_ID, CLIENT_SECRET),
        params=params,
        headers=headers,
    )
    token = json.loads(res.content)
    token["session_id"] = request.cookies["session_id"] # IndexError: 'session_id' doesn't exist

    db_token = models.Token(**token)

    db.add(db_token)
    db.commit()
    db.refresh(db_token)

    return

However, I can't access the session_id in /callback: the request.cookies is {}, which kind of makes sense because the caller is the external API and not the client. I'm not sure how I can create a session_id that I can share with the client, either through a cookie or some other way.

DSteman
  • 1,388
  • 2
  • 12
  • 25
  • My memory might be wrong, but isn't the _client_ the one doing the callback? Not the external service? In that case, cookies _should be included_, but it would depend on how the request to your `/callback` URL is made. – MatsLindh Mar 25 '23 at 11:38
  • You are actually right, I changed the first paragraph. However, I still don't understand why `request.cookies["session_id"]` is not available in the `callback`... – DSteman Mar 25 '23 at 12:18
  • 1
    On a side note, I would not suggest using Python `requests` within an `async def` endpoint. Please have a look at [this answer](https://stackoverflow.com/a/71517830/17865804), as well as [here](https://stackoverflow.com/a/73736138/17865804) and [here](https://stackoverflow.com/a/74239367/17865804) – Chris Mar 25 '23 at 12:28
  • 1
    Start by inspecting _whether the cookie has actually been set_ in your browser's development tools, then look at the headers for the request - is a `Cookie:` header included? Does the initial response include a `Cookie` header if not? i.e. start by narrowing down where the issue happens. – MatsLindh Mar 25 '23 at 13:54
  • Yes I realised some details are missing. I'll investigate a bit further and provide a leaner reproducible example. – DSteman Mar 26 '23 at 03:33
  • These comments already gave me some direction :) – DSteman Mar 26 '23 at 04:02

0 Answers0