I have a FastAPI backend and a NextJS frontend. I ...
# support-questions-legacy
c
I have a FastAPI backend and a NextJS frontend. I want to use getServerSideProps to send the logged in user's data to my frontend. When I try to get the logged in user's data in getServerSideProps, I get { message: 'unauthorised' }. I think this is because the cookies in the browser are not sent to my FastAPI backend. Is this even possible?
r
Hey @chunkygoo. yea. This is possible.
Checkout the session section -> sharing sessions across multiple api domains
Copy code
import EmailPasswordReact from 'supertokens-auth-react/recipe/emailpassword';
import EmailVerification from 'supertokens-auth-react/recipe/emailverification';
import SessionReact from 'supertokens-auth-react/recipe/session';
import { appInfo } from './appInfo';
import Router from 'next/router';

export const frontendConfig = () => {
  return {
    appInfo,
    recipeList: [
      EmailPasswordReact.init({
        signInAndUpFeature: {
          disableDefaultUI: true,
        },
        style: {
          button: {
            backgroundColor: '#0076ff',
            border: '0px',
            margin: '0 auto',
          },
        },
      }),
      EmailVerification.init({
        mode: 'REQUIRED',
      }),
      SessionReact.init({
        cookieDomain: 'localhost',
        sessionScope: 'localhost',
      }),
    ],
    // this is so that the SDK uses the next router for navigation
    windowHandler: (oI) => {
      return {
        ...oI,
        location: {
          ...oI.location,
          setHref: (href) => {
            Router.push(href);
          },
        },
      };
    },
  };
};
Copy code
export async function getServerSideProps(context) {
  let res = await getCurrentUser();
  console.log(res.data);
  return {
    props: { userId: 1 },
  };
}
Still prints { message: 'unauthorised' }
r
Hey! There is another page for sharing a session across api domains. You want to see that one.
c
Is it this one?
So I also need to do a supertokens init in my nextjs api even though I am using a fastapi backend?
Hi @rp_st , so I have a fastapi endpoint that checks for an existing session and returns a user if the session is valid. I also have a Nextjs frontend that works fine retrieving the user after the user has logged in. However, when I try to fetch the user in getServerSideProps, the httponly, secure cookies are not being sent to the fastapi endpoint. This is because the request inside getServerSideProps does not run in the browser, see https://stackoverflow.com/questions/69057271/why-are-cookies-not-sent-to-the-server-via-getserversideprops-in-next-js. In order to work around this, is there a way to manually set httponly cookies so that my fastapi endpoint can see them in Depends(verify_session())?
I am able to get the cookies in getServerSideProps, just unable to pass them in the right way so that the fastapi endpoint can see them
`export async function getServerSideProps(context) { let res = {}; let _res; try { let myAxios = await myAxiosPrivate(); _res = await myAxios .get(
/users/me
, { headers: { Cookie: context.req.cookies, }, }) .catch((e) => { return e.response; }); console.log(_res); } catch (error) { console.log(error); } res.status = _res.status; res.data = _res.data; return { props: { _res: res, }, }; } `
So context.req.cookies, returns the cookies like sAccessToken etc
r
Right. Can you enable backend debug logs in fast api and show me the output when you make this api call?
c
INFO: Will watch for changes in these directories: ['/home/calvin/Downloads/SportsConnectBackend'] INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) INFO: Started reloader process [1329383] using WatchFiles com.supertokens {"t": "2022-09-26T03:27:45.684Z", "sdkVer": "0.11.0", "message": "Started SuperTokens with debug logging (supertokens.init called)", "file": "supertokens.py:207"} com.supertokens {"t": "2022-09-26T03:27:45.684Z", "sdkVer": "0.11.0", "message": "app_info: { "api_base_path": "/auth", "api_domain": "http://localhost:8001", "api_gateway_path": "", "app_name": "SportsConnect", "framework": "fastapi", "mode": "asgi", "website_base_path": "/auth", "website_domain": "http://localhost:3000" }", "file": "supertokens.py:210"} com.supertokens {"t": "2022-09-26T03:27:45.684Z", "sdkVer": "0.11.0", "message": "framework: fastapi", "file": "supertokens.py:211"} com.supertokens {"t": "2022-09-26T03:27:45.685Z", "sdkVer": "0.11.0", "message": "session init: anti_csrf: NONE", "file": "recipe/session/recipe.py:101"} com.supertokens {"t": "2022-09-26T03:27:45.685Z", "sdkVer": "0.11.0", "message": "session init: cookie_domain: localhost", "file": "recipe/session/recipe.py:103"} com.supertokens {"t": "2022-09-26T03:27:45.685Z", "sdkVer": "0.11.0", "message": "session init: cookie_same_site: lax", "file": "recipe/session/recipe.py:108"} com.supertokens {"t": "2022-09-26T03:27:45.685Z", "sdkVer": "0.11.0", "message": "session init: cookie_secure: True", "file": "recipe/session/recipe.py:111"} com.supertokens {"t": "2022-09-26T03:27:45.685Z", "sdkVer": "0.11.0", "message": "session init: refresh_token_path: /auth/session/refresh ", "file": "recipe/session/recipe.py:114"} com.supertokens {"t": "2022-09-26T03:27:45.685Z", "sdkVer": "0.11.0", "message": "session init: session_expired_status_code: 401", "file": "recipe/session/recipe.py:118"}
INFO: Started server process [1329385] INFO: Waiting for application startup. INFO: Application startup complete. com.supertokens {"t": "2022-09-26T03:27:47.414Z", "sdkVer": "0.11.0", "message": "middleware: Started", "file": "supertokens.py:536"} com.supertokens {"t": "2022-09-26T03:27:47.415Z", "sdkVer": "0.11.0", "message": "middleware: requestRID is: None", "file": "supertokens.py:549"} com.supertokens {"t": "2022-09-26T03:27:47.415Z", "sdkVer": "0.11.0", "message": "middleware: Checking recipe ID for match: session", "file": "supertokens.py:573"} com.supertokens {"t": "2022-09-26T03:27:47.415Z", "sdkVer": "0.11.0", "message": "middleware: Checking recipe ID for match: emailpassword", "file": "supertokens.py:573"} com.supertokens {"t": "2022-09-26T03:27:47.415Z", "sdkVer": "0.11.0", "message": "middleware: Checking recipe ID for match: emailverification", "file": "supertokens.py:573"} com.supertokens {"t": "2022-09-26T03:27:47.415Z", "sdkVer": "0.11.0", "message": "middleware: Not handling because no recipe matched", "file": "supertokens.py:586"}
INFO: 127.0.0.1:54330 - "GET /auth/csrf_token HTTP/1.1" 200 OK com.supertokens {"t": "2022-09-26T03:27:47.418Z", "sdkVer": "0.11.0", "message": "middleware: Started", "file": "supertokens.py:536"} com.supertokens {"t": "2022-09-26T03:27:47.418Z", "sdkVer": "0.11.0", "message": "middleware: Not handling because request path did not start with config path. Request path: /users/me", "file": "supertokens.py:543"} com.supertokens {"t": "2022-09-26T03:27:47.419Z", "sdkVer": "0.11.0", "message": "getSession: Started", "file": "recipe/session/recipe_implementation.py:241"} com.supertokens {"t": "2022-09-26T03:27:47.419Z", "sdkVer": "0.11.0", "message": "getSession: rid in header: False", "file": "recipe/session/recipe_implementation.py:243"} com.supertokens {"t": "2022-09-26T03:27:47.419Z", "sdkVer": "0.11.0", "message": "getSession: request method: GET", "file": "recipe/session/recipe_implementation.py:246"} com.supertokens {"t": "2022-09-26T03:27:47.419Z", "sdkVer": "0.11.0", "message": "getSession: UNAUTHORISED because idRefreshToken from cookies is undefined", "file": "recipe/session/recipe_implementation.py:255"} com.supertokens {"t": "2022-09-26T03:27:47.420Z", "sdkVer": "0.11.0", "message": "errorHandler: Started", "file": "supertokens.py:610"} com.supertokens {"t": "2022-09-26T03:27:47.420Z", "sdkVer": "0.11.0", "message": "errorHandler: Error is from SuperTokens recipe. Message: Session does not exist. Are you sending the session tokens in the request as cookies?", "file": "supertokens.py:611"} com.supertokens {"t": "2022-09-26T03:27:47.420Z", "sdkVer": "0.11.0", "message": "errorHandler: Checking recipe for match: session", "file": "supertokens.py:622"} com.supertokens {"t": "2022-09-26T03:27:47.420Z", "sdkVer": "0.11.0", "message": "errorHandler: Matched with recipeID: session", "file": "supertokens.py:628"}
com.supertokens {"t": "2022-09-26T03:27:47.420Z", "sdkVer": "0.11.0", "message": "errorHandler: returning UNAUTHORISED", "file": "recipe/session/recipe.py:230"} com.supertokens {"t": "2022-09-26T03:27:47.420Z", "sdkVer": "0.11.0", "message": "Sending response to client with status code: 401", "file": "utils.py:134"} INFO: 127.0.0.1:54342 - "GET /users/me HTTP/1.1" 401 Unauthorized
FYI, I call my own anti_csrf token endpoint before each request
r
Can you print out the request in the fastapi layer? It seems cookies are not being sent to it.
c
Yes the cookies are not being sent. That’s the problem, I can’t print anything out since I’m using the verify_session() injection via Depends
This only happens in getserversideprops, as it’s not sending the httponly cookies stored in the browser automatically
r
The getServerSideProps gets the incoming cookies?
c
Yeap
I can print them out and see them in the context.req object
r
Can you try explicitly setting the cookies instead of just passing all
sAccessToken
c
But where do I set them?
r
And sIdRefreshToken
c
Is it headers?
r
In cookies
c
This is how I am setting them right now
In “Cookie”, which itself in “headers”
r
Yes. So since that’s a not working maybe try explicitly setting those values
c
So the way I’m setting them is right?
In headers and in cookies?
r
Yes I thought it was right. But it’s not working, so it’s not right
Maybe google how to set cookies in request
c
Cause I thought there might be another way to pass httponly + secure cookies
r
Not really
c
That supertoken’s verify_session need
r
You just need to pass sAccessToken and sIdRefreshToken as cookies.
c
Ok
I will try that
I’m a little confused. When we set the cookies attribute httponly=true, it means that only the server is allowed to access the cookie right?
If I extract it in getserversideprops, and set it in the header, will it still be sent correctly? Does it have to be sent from the browser if httponly=True?
r
It doesn’t have to be sent from the browser in case httponly is true. You can send it in server side props to your api as well
But you have to send it as cookies
c
But I have to set it to be httponly=True?
r
U don’t
You should try and explicitly set those cookies instead of equating it to req.cookies
c
Ah! Ok
r
And the cookies you want to set are sAccessToken and sIdRefreshToken
Both of which should be available in req.cookies
c
it seemed to have worked but now I am getting this { message: 'try refresh token' } occasionally
I thought Session.addAxiosInterceptors(myAxios); would've taken care of that?
r
right yea.. so that interceptor is on the frontend and doesn't run in getServerSideProps
so what you want to do is, if you get a 401 from the fastapi, you want to send
return { props: { fromSupertokens: 'needs-refresh' } }
from the
getServerSideProps
function (as shown here: https://supertokens.com/docs/thirdpartyemailpassword/nextjs/session-verification/in-ssr) And then that should trigger the refresh from the frontend (Assuming that you have followed the nextjs guide)
c
Gotcha!
Let me try that
r
cool!
yea.. the docs are a little sparse when it comes to properly forwarding requests from getServerSideProps
c
No worries, do I just return { props: { fromSupertokens: 'needs-refresh' } } and it will automatically refresh? It doesn't seem to do that still...
`export async function getServerSideProps(context) { let res = {}; let _res; let cookieString = ''; for (var key of Object.keys(context.req.cookies)) { cookieString += key + '=' + context.req.cookies[key] + '; '; } try { let myAxios = await myAxiosPrivate(); _res = await myAxios .get(
/users/me
, { headers: { Cookie: cookieString, }, }) .catch((e) => { return e.response; }); if (_res.status === 401) { return { props: { fromSupertokens: 'needs-refresh' } }; } res.status = _res.status; res.data = _res.data; } catch (error) { console.log(error); } if (res) { return { props: { _res: res, }, }; } return {}; }`
res (not _res) is still undefined when I log it out after the token first expire
nevermind I think I needed to add something to the frontend too
Copy code
useEffect(() => {
    let refresh = async () => {
      if (pageProps.fromSupertokens === 'needs-refresh') {
        if (await Session.attemptRefreshingSession()) {
          location.reload();
        } else {
          router.push('/auth/loginsignup');
          redirectToAuth();
        }
      }
    };
    refresh();
  }, [pageProps.fromSupertokens, router]);
Is location.reload() the only option here?
I'm using nextjs and don't really want to reload() if possible
r
If there is a way to trigger a reload via the nextjs router (such that the getServerSideProps is called again), then you can use that.
c
Got it
Thanks for your help, rp! You've been really helpful 🙂
managed to replace reload() with this router.replace(router.asPath);
r
cool!
19 Views