skip to Main Content

I have a spring boot backend running in a separate docker container that uses a JSESSIONID cookie for authentication, which I can see in the browser. However when my frontend svelte.js container running on a different port makes a request to my backend using fetch() , it doesn’t appear as if the cookie from the browser is being attached. This is despite setting {credentials:’include’} as found on another stack overflow post here . How can I attach the cookie in my browser when I am sending a request from my frontend svelte docker container to my backend spring container?

Here is my server side svelte code (this does not run on the browser, but rather inside of the docker container)

 
/** @type {import('./$types').PageServerLoad} */
export async function load({ params }) {
    const response = await fetch(`${getBaseUrl()}/api/draftgroups`,{credentials:'include',method:'get'});

    let txt = await response.text()
    if(response.headers.get("content-type") != "application/json") {
    
    // this will determine if user is logged in. If not logged in, the user will be redirected to sign in with    // google through OAuth, and thus the response type will be html rather than json for the redirection
       console.log("NOT SIGNED IN")
        throw redirect('302',`http://localhost:6868/login`)
    
    }
    if (!response.ok) {
        throw new Error(`Error! status: ${response.status}`);
    }

    let responseJSON = await response.json()

    return responseJSON
}

The if statement that checks the content type of the text will determine whether the user is logged in or not, as they will be prompted to sign in with google with OAuth if they are not signed in, which will give an html response. I would only expect the if condition to fire the first time the user visits the page, since they haven’t authenticated with OAuth. However I found that each subsequent time they visited the page, it appeared that the html response directing the user to sign in through google was printed, which means that the user’s authenticated cookie wasn’t attached to the request.

Does this have to do with the two different docker containers being different origins for the cookie (i.e. the spring boot container and the svelte container)? And how can I fix this

Here is my docker-compose.yml to show my infrastructure:

# Based off of https://github.com/bezkoder/docker-compose-nodejs-mongodb/tree/master/bezkoder-app
# https://www.bezkoder.com/docker-compose-nodejs-mongodb/

version: "3.8"
services:
  mongodb:
    image: mongo:5.0.2
    restart: unless-stopped
    ports:
      - 27017:27017
    volumes:
      - db:/data/db

  spring-boot:
    image: bracket_backend
    build:
      context: ./backend
      dockerfile: Dev.Dockerfile
    depends_on:
      - mongodb
    ports:
      - 6868:8080
    stdin_open: true
    tty: true
    volumes: 
      - ./backend/src:/app/src
      
  frontend-svelte:
    image: bracket_frontend
    build:
      context: ./frontend-svelte
      dockerfile: Dev.Dockerfile
    ports:
      - 1234:8080
    stdin_open: true
    tty: true
    volumes:
      - ./frontend-svelte/src:/app/src
    depends_on:
      - spring-boot


volumes:
  db:

2

Answers


  1. Chosen as BEST ANSWER

    Thanks to John Williams for the idea! Here is full working code:

    /** @type {import('./$types').PageServerLoad} */ export async function load({ cookies }) {
        let jSessionId = cookies.get('JSESSIONID')
        cookies.set('JSESSIONID',cookies.get('JSESSIONID'))
        let request = fetch(`${getBaseUrl()}/api/draftgroups`,
        {headers:{
            Cookie : `JSESSIONID=${jSessionId}`
        }});
        const response = await request
    
        let txt = await response.text()
        if(response.headers.get("content-type") != "application/json") {
            // this will determine if user is logged in. If not logged in, the user will be redirected to sign in with    
            // google through OAuth, and thus the response type will be html rather than json for the redirection
            throw redirect(302,`http://localhost:6868/login`)
        }
        if (!response.ok) {
            throw new Error(`Error! status: ${response.status}`);
        }
    
        let responseJSON = await response.json()
    
        return responseJSON }
    

    A few clarifications based on things I ran into while implementing his solution that should hopefully help others facing the same thing:

    1. It doesn't appear that httpOnly cookies aren't relevant here since the cookies are being referenced here from the Svelte Server instead of the browser's document.cookie. I wasn't able to figure out how to turn off httpOnly for the JSESSIONID cookie in my backend, but it didn't seem to be an issue. I think this would apply with any server side js framework like next, nuxt, etc. though please correct me if wrong or if I am not understanding httpOnly cookies.
    2. Using fetch it is possible to pass a cookie with the headers option as an additional possibility to what John suggested above with XMLHttpRequest. See my code sample above.

    Hope this helps!


  2. The response from svelte load function is not passing the JSESSIONID back to the browser. Also, the credentials include solution is for the scenario where the browser is communicating directly with the cookie origin. That is not the case here because you have an intervening layer (the svelte server) and two separate sets of credentials so almost everything you get from SO searches does not apply.

    You are stripping everything but the JSON body from the response. You need to get the end-server cookie back to the browser. This is difficult but I can provide pointers.

    In order for svelte to pass back the cookie your load function needs a signature like this load({ request, cookies })

    The svelte load function must pass-through the JSESSIONID cookie received by it’s call here:

    const response = await fetch(`${getBaseUrl()}/api/draftgroups`,{credentials:'include',method:'get'});
    

    Get the cookie contents, unless it’s marked as httpOnly, with the following:

    const cookie = response.headers.get('set-cookie');
    

    The JSESSIONID cookie should be here.

    Include it in svelte load function response:

    cookies.set(
    

    That’s only half of the solution. The JSESSIONID cookie now on the oncoming request from the browser needs to be added to the request to api/draftgroups:

    Get it from the cookies argument of the load function and add to to the fetch to the server by setting a cookie header. This may not be possible with fetch so you may need to use XMLHttpRequest

    headers: {“Cookie” : [cookie-name=value]}
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search