mux icon indicating copy to clipboard operation
mux copied to clipboard

[bug] Headers are not accessible in Middleware when Request sent from Browser

Open akki4vedi opened this issue 2 years ago • 10 comments

Describe the bug

A clear and concise description of what the bug is. I am learning to add middleware in mux Router. I am getting token from request header and verifying it with hard written string. It is working fine when I send the request from Postman, but when I send the request from the web page, it never fetches the header in middleware. I have tried to send the request using all three methods fetch(), jquery ajax(), and Axios. But the result is same all the time. …

Versions

Go version: 1.19.1 package version: v1.8.0 (gorilla/mux version)

Steps to Reproduce

send the request from browser. I am using Google Chrome v106.0.5249.103 (Official Build) (64-bit)

Expected behavior

value of header sent from browser …

Code Snippets

A minimum viable code snippet can be useful! (use backticks to format it).

var userColl = make(map[string]string)

func main() {
	userColl["userTokenForA"] = "a"
	userColl["userTokenForB"] = "b"

	handleRequests()
}

func handleRequests() {
	router := mux.NewRouter().StrictSlash(true)
	router.PathPrefix("/public").Handler(http.StripPrefix("/public/", http.FileServer(http.Dir("./public/"))))
	router.Use(authenticate)
	router.HandleFunc("/todo", db.GetAllLists).Methods("GET")
	log.Fatal(http.ListenAndServe(":4010", router))
}
func authenticate(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

		token := r.Header.Get("authentication")
		user := userColl[token]
		fmt.Println("token", token, "user", user)
		w.Header().Set("Content-Type", "application/json")
		if user != "" { //&& userColl[token] == userId {
			fmt.Println("authorized...")
			r.Header.Set("user", user)
			next.ServeHTTP(w, r)
		} else {
			w.WriteHeader(http.StatusUnauthorized)
			json.NewEncoder(w).Encode(bson.M{
				"ERROR": "AUTHENTICATION FAILED",
			})
		}
	})
}

Front End :-

(()=> {
	axios("/todo", {
				method: "GET",
				headers: {
					authentication: "userTokenForA",
					"Content-Type": "application/json",
				},
	})
	.then((res) => {
		console.log("res", res)
	})
	.catch((err) => {
		console.log("error", err)
         })
})()

akki4vedi avatar Nov 21 '22 14:11 akki4vedi

Hey @akki4vedi, I went through the given code. I found an issue in the current implementation that (though it is the correct intended behaviour) authenticate middleware is applied on all the routes.

Technically speaking, when you're making a request to any route containing the public prefix middleware applies and expects you to send header authentication reason as mentioned before the middleware is applied on all the routes. If the header is missing it will return the status http.StatusUnauthorized on the static content page.

I'm guessing this is not what you want. Just to be clear If I'm not wrong you want static routes to be served without authentication. I would highly recommend you to go through the issue https://github.com/gorilla/mux/issues/360

I tried the same and it is working fine. Attaching a screenshot for reference. Screenshot 2022-11-29 at 3 37 57 AM

I hope this helps and solves your problem. If yes, please close this issue else I would be happy to answer your doubts/queries. Thank you 🙌🏻

amustaque97 avatar Nov 28 '22 22:11 amustaque97

Thanks for the reply. Actually, I don't want to deactivate API for any route, there is only one route in my project to test authenticate middleware. So I am testing it and I am not able to get headers in the middleware, only when I send the request from Browser. When I send the request from Postman, It works fine. I can see that your middleware is perfectly working as your log msg is showing the value of userColl. This is not happening with my code. As I mentioned in the issue, I've tried sending the request in all three ways (fetch(), jquery ajax(), and Axios).

akki4vedi avatar Dec 01 '22 11:12 akki4vedi

What I have shown in the screenshot is from the browser only using the fetch API. Just that I need to add an exception to the static route in the middleware. As I mentioned before if you're not adding conditions for the static route, it will require an authentication header to be passed while making a request to the static endpoint from the browser.

amustaque97 avatar Dec 01 '22 11:12 amustaque97

I am passing the authentication header in the request. image

But still, not able to read it in middleware. image

This message is logged when I send the request from Postman. image

I am not understanding why It's not working.

akki4vedi avatar Dec 01 '22 12:12 akki4vedi

Hi @akki4vedi Since StrictSlash is true, this may be due to a redirect when accessing with /todo. Could you try accessing /todo/ once?

soundkitchen avatar Dec 03 '22 16:12 soundkitchen

Hey @soundkitchen, I don't think it will work. I tried it and didn't get the expected output.

I'm sharing my screenshot for reference. We need to send the authentication header when hitting the URL /public from the browser.

In chrome browser {"ERROR":"AUTHENTICATION FAILED"} is from the code where I have written javascript code to hit /todo/ (note the strict slash).

Chrome dev tools console shows what I'm trying to say(on how we should send requests) if we don't want to exclude /public routes.

image

It doesn't matter if we're using fetch, axios or any other library. Middleware by definition is applied to all the routes. cc @akki4vedi

amustaque97 avatar Dec 04 '22 20:12 amustaque97

I've tried adding a slash in the route but still, it's not working. Here I'm attaching two screenshots of headers in middleware and in route,

  1. Headers in authenticate middleware image
  2. Headers in /todo route without authenticate middleware image

akki4vedi avatar Dec 05 '22 09:12 akki4vedi

@akki4vedi I wrote the code and ran it, but I was able to get the headers in Middleware.

The first screenshot you pasted doesn't seem to have a Referrer, under what circumstances was this requested? As long as the request is made from a browser using JavaScript, I would expect the Referrer to be present, but is there an exception?

soundkitchen avatar Dec 05 '22 10:12 soundkitchen

I am simply calling the fetch API on load of javascript on the HTML page, the code is written in the issue as Front End. @soundkitchen & @amustaque97 Can I have code of API call in your app and the main method of the server for reference?

akki4vedi avatar Dec 05 '22 12:12 akki4vedi

@akki4vedi The code I used for verification is below. I have tried to make it as similar to your code as possible. gorilla_mux_703.zip

soundkitchen avatar Dec 06 '22 06:12 soundkitchen