Unable to get cookie data from Go server using React
P粉360266095
P粉360266095 2024-04-06 13:09:26
0
1
499

After React I started getting into the backend and added github OAUTH and sessions on the backend server to save data. They all work fine on the backend and I can access the data from other handlers via sessions etc. But once I try to get the session from the backend using React, I can never do it.

func (h Handler) HandleAuth(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Access-Control-Allow-Origin", "http://127.0.0.1:5173")
    w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
    w.Header().Set("Access-Control-Allow-Methods", "GET")
    url := Oauth2Config.AuthCodeURL("state", oauth2.AccessTypeOffline)
    http.Redirect(w, r, url, http.StatusFound)
}

func (h Handler) HandleAuthCallback(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Access-Control-Allow-Origin", "http://127.0.0.1:5173")
    w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
    w.Header().Set("Access-Control-Allow-Methods", "GET")
    code := r.URL.Query().Get("code")
    token, err := Oauth2Config.Exchange(r.Context(), code)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    // Use the access token to get the user's GitHub data
    client := github2.NewTokenClient(r.Context(), token.AccessToken)
    user, _, err := client.Users.Get(r.Context(), "")
    if err != nil {
        fmt.Printf("Error: %v\n", err.Error())
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    session, err := store.Get(r, "session")
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    session.Values["user"] = user.GetLogin()
    session.Values["access_token"] = token.AccessToken
    err = session.Save(r, w)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    fmt.Fprintf(w, "this is authcallback: %s", user.GetLogin())

}

func (h Handler) HandleCurrentUser(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Access-Control-Allow-Origin", "http://localhost:5173")
    w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
    w.Header().Set("Access-Control-Allow-Methods", "GET")
    session, err := store.Get(r, "session")
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    user, ok := session.Values["user"].(string)
    if !ok {
        http.Error(w, "Invalid user in session", http.StatusInternalServerError)
        return
    }
    // Set the content type header to JSON
    w.Header().Set("Content-Type", "text/plain")

    // Write the JSON data to the response
    w.Write([]byte(user))
}

I tried a lot of things, first I used a different session library than gorilla, it's called scs, I thought it might be my library, but it's not the case. When changing the code I get different errors but the backend works fine every time. On API requests from the backend sometimes I get an empty string data, or a network error or user not found etc, but every time I check the backend in every iteration of the code it works fine. This is the get request:

function App() {
    const [user, setUser] = useState(null);

    useEffect(() => {
        fetch('http://127.0.0.1:3080/user', {
            method: 'GET',
        })
            .then(response => response.text())
            .then(data => {
                setUser(data);
                console.log(data);
            })
            .catch(error => console.error(error));
    }, []);
[]);
    return <>
    <p>Logged in as: {user}</p>
            <button onClick={() => window.location.href = 'http://127.0.0.1:3080/oauth'}>Login</button>

    </>
}

P粉360266095
P粉360266095

reply all(1)
P粉237029457

IIUC, the web page loads from http://localhost:5173 and makes a GET request to http://127.0.0.1:3080/user. So this is a cross-origin request.

By default, the browser does not send credentials (such as Cookie and HTTP Authentication) in cross-origin XMLHttpRequest or Fetch calls. Certain flags must be set when calling the XMLHttpRequest object or the Request constructor.

To tell the browser to send cookies to cross-domain URLs, the fetch call should be changed like this:

fetch('http://127.0.0.1:3080/user', {
    method: 'GET',
+   mode: 'cors',
+   credentials: 'include',
  })

For more information, see Requests with Credentials.

It looks like the backend code has the CORS headers configured correctly, so the above changes should make it work. If not, check your browser's DevTools console. It should contain some error/warning messages telling you what went wrong.


This is a minimal demo to help debug the issue.

  1. Start the server: go run main.go

  2. Navigate to http://127.0.0.1:3080/callback in your browser to set the cookie.

    Set-Cookie: session=abc;Path=/;Expires=Tuesday, April 18, 2023 18:34:49 GMT;Maximum age=86372;Http only;SameSite=Lax.

  3. Navigate to http://127.0.0.1:5173/ to open the page.

  4. Click the Get button on this page. It should output the session cookie "abc" to the DevTools console.

Comments:

I just realized that the cookie is being saved to domain 127.0.0.1 (no port). So http://127.0.0.1:5173/ page can also read cookies.

package main

import (
    "fmt"
    "net/http"
    "time"
)

func main() {
    go func() {
        _ = http.ListenAndServe(":5173", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            w.Write([]byte(page))
        }))
    }()

    http.HandleFunc("/callback", func(w http.ResponseWriter, r *http.Request) {
        http.SetCookie(w, &http.Cookie{
            Name:     "session",
            Value:    "abc",
            Path:     "/",
            Expires:  time.Now().Add(24 * time.Hour),
            MaxAge:   86372,
            HttpOnly: true,
            SameSite: http.SameSiteLaxMode,
        })
        w.Write([]byte("done"))
    })

    http.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Access-Control-Allow-Origin", "http://127.0.0.1:5173")
        w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
        w.Header().Set("Access-Control-Allow-Methods", "GET")
        w.Header().Set("Access-Control-Allow-Credentials", "true")

        cookie, err := r.Cookie("session")
        if err != nil {
            fmt.Fprintln(w, err.Error())
            return
        }
        w.Write([]byte(cookie.Value))
    })

    http.ListenAndServe(":3080", nil)
}

const page = `
  
    
    sssccc
  
`

Incognito windows cannot see the cookies of other windows. Please check your browser to make sure the cookie is present.

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template