How to get svelte to save a JWT cookie

This has been plaguing me all day, so I’m saving some instructions here for future reference.

For my project i’m creating a Svelte front end and a Go backend. I’m using JWT for authentication and I want to store the JWT in a cookie. The flow should go like this:

  • User logs in by sending a POST request to my sign in endpoint.
  • The backend checks the credentials and if they’re valid, it creates a JWT and sends it back in a cookie as Set-Cookie.
  • The front end receives the cookie and stores it in the browser.
  • The front end sends the JWT cookie with every request to the backend.

I’ve been trying to get the cookie to save in the browser for ages and I finally figured it out.

Debugging steps:

The requests made by the client should have credentials: 'include', set.

You’ll need to make sure you’ve got credentials: 'include', set on your requests. This will allow the browser to send the cookie with every request. NOTE: You also need to send this with the request that sets the cookie.

1
2
3
4
5
6
7
8
9
10
11
const res = await fetch(API_ENDPOINTS.LOGIN, {
    method: 'POST',
    credentials: 'include',
    headers: {
        'Content-Type': 'application/json'
    },
    body: JSON.stringify({
        email: email.value,
        password: password.value
    })
});

You need to set the CORS headers on the backend.

This is pretty easy in golang with gin. NOTE: You can’t use wildcards for a request that contains credentials.

	r := gin.Default()
	config := cors.DefaultConfig()
	// config.AllowOrigins = []string{"http://localhost:5000"}
	if APIHandler.Config.LocalDev {
		config.AllowOrigins = APIHandler.Config.TestConfig.CORSOrigins
	} else {
		config.AllowOrigins = APIHandler.Config.CORSOrigins
	}
	config.AllowCredentials = true
	r.Use(cors.New(config))

You need to make sure HTTPS is set to false when you’re doing local dev.

In short, locally developing your frontend with a backend deployed and using HTTPS is a massive pain. I’d recommend running both your F/E and B/E locally and setting HTTPS to false on the backend for development.

	c.SetCookie(
		"bearer",
		tokenString,
		h.Config.TokenExpirationTimeMinutes*60,
		"/", // This is important, sets the cookie for the whole domain.
		h.Config.SiteDomain, // This is important too, your frontend and backend need to be on the same domain.
		h.Config.UseSSL, // Set this to false for local dev.
		true,  // This decides whether your JS can access the cookie. Bad for security if false, se to true.
	)