I’m developing a web application in Go that utilizes the net/http package for handling HTTP requests. I have a login system set up where, upon successful authentication, the user is redirected to an authorization page. However, I’m encountering issues with persisting the session state across redirects.
Here’s a simplified version of my code:
func loginHandler(w http.ResponseWriter, r *http.Request) {
if dumpVar {
_ = dumpRequest(os.Stdout, "login", r)
}
//Start store
store, err := session.Start(r.Context(), w, r)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
//If form is submitted (POST request)
if r.Method == "POST" {
//Pares form data
if r.Form == nil {
if err = r.ParseForm(); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
username, password, ok := r.BasicAuth()
if !ok {
w.WriteHeader(500)
w.Write([]byte("Could not read username and password from header"))
}
log.Printf("username in /login: %s", username)
log.Printf("passsword in /login: %s", password)
userID, err := srv.PasswordAuthorizationHandler(context.Background(), "ID", username, password)
//userID, err := srv.PasswordAuthorizationHandler(context.Background(), "ID", r.Form.Get("username"), r.Form.Get("password"))
log.Printf("userID in /login: %s", userID)
if len(userID) != 0 {
// Store logged-in user ID in store
store.Set("LoggedInUserID", interface{}(username))
//store.Set("LoggedInUserID", r.Form.Get("username"))
err = store.Save()
log.Printf("session in /login: %v", store)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Redirect to authorization page
w.Header().Set("Location", "/authorize")
w.WriteHeader(http.StatusFound)
return
} else {
tmpl, err := template.ParseFiles(conf.Config.PathHtml + "login.html")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
err = tmpl.Execute(w, nil)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
return
}
}
//Render login HTML page
tmpl, err := template.ParseFiles(conf.Config.PathHtml + "login.html")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
err = tmpl.Execute(w, nil)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
func authHandler(w http.ResponseWriter, r *http.Request) {
if dumpVar {
_ = dumpRequest(os.Stdout, "authHandler", r) // Ignore the error
}
// Start store
store, err := session.Start(nil, w, r)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
log.Printf("session in /authorize: %v", store)
// Check if user is logged in
if _, ok := store.Get("LoggedInUserID"); !ok {
// If not logged in, redirect to login page
w.Header().Set("Location", "/login")
w.WriteHeader(http.StatusFound)
return
}
// Render authorization HTML page
tmpl, err := template.ParseFiles(conf.Config.PathHtml + "auth.html")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
err = tmpl.Execute(w, nil)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
The issue arises when I redirect from the login handler to the authorization handler. Despite starting a session in the login handler and setting a value (LoggedInUserID), it seems like the session data is lost during the redirect, as the authorization handler can’t detect the user’s logged-in state.
I’m trying to implement OAuth for authentication, and I have a React client that initializes the OAuth flow. After successful authentication with the OAuth provider, the user is redirected back to the authorization page (/authorize).
I’ve tried using different session storage mechanisms (e.g., cookies, memory-based sessions), but none seem to resolve the problem. Is there something I’m missing in my implementation, or is there a better approach to persisting session state across redirects in Go?
Any help or insights would be greatly appreciated. Thank you!
user24933717 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.