javascriptjwtsveltesveltekit

Token is generated at the endpoint but does not arrive on the page


I want to create a website with Svelte/Kit and use JWT. I have found instructions on the internet, for example: Svelte JWT Authentication https://morioh.com/p/1d95522418b2 SvelteKit Session Authentication Using Cookies https://www.youtube.com/watch?v=bG7cxwBMVag But unfortunately no instructions for Svelte Kit and JWT. So I tried it myself.

The token is generated at the endpoint, but does not arrive on the page (or is not callable). I suspect that some setting in the headers is wrong, but can't figure out what is wrong. This is my highly simplified test environment:

(1) I call the endpoint login.js from the page index.svelte. For testing, I omit checking email and password and send JWT right back. Data arrives, but I don't see the JWT.

(2) The JWT should be sent to another endpoint. What is the best way to do this?

The "page" index.svelte (simplified):

<script>
  let email="", password="";
    
  const doLogin = async () => {
    const response = await fetch("/auth/login", {
      method: 'POST',
      headers: {
    "Content-Type": "application/json",
      },
      credentials: 'include',
      body: JSON.stringify({
    email,
    password
      })
    }); 
    
    if (response.status == 200) {
      const { done, value } = 
        await response.body.getReader().read();
      await console.log("done, value=", done, 
        JSON.parse(new TextDecoder("utf-8").decode(value)));
      await console.log("headers=", response.headers);
    }
  }
</script>

<h1>Welcome to MyAuth</h1>
<input type=email bind:value={email}/><br/>
<input type=password bind:value={password}/><br/>
<button on:click={doLogin}>Submit</button>

The "endpoint" login.js (simplified):

import jwt from "jsonwebtoken";  

export function post(request, context) {
  const token = jwt.sign({
    data: { text: "test" },
    "topsecret", 
  });  
    
  const response = {
    status: 200,
    headers: {
      'content-type': 'application/json',
      'Authorization': `Bearer ${token}`,
    },
    body: {
      passwordOk: true,
    }
  };
  return response;
}

The console shows:

done, value= false {passwordOk: true}
index.svelte:59 headers= HeadersĀ {}
index.svelte:44 Fetch finished loading: POST "http://localhost:3000/auth/login".
doLogin @ index.svelte:44

Solution

  • I think you are mixing up the two major parts to authentication:

    1. Requesting/sending credentials.
    2. Using those credentials to access protected content.

    Authorization: Bearer ${token} is normally sent from the (browser) client to the server to request access to protected content. So right now, your server is asking the client for permission. This doesn't make sense.

    Instead, the login endpoint should send the token via:

    Set-Cookie causes the browser to send this value as a cookie with every future request. The server can check for this cookie value before serving protected content. This can be more secure because you can send an HTTP only cookie.

    If the token is sent in the body of the response to login the client should send the token in future requests with the Authorization: Bearer ${token} header. The server can then check for this header before serving protected content.