2

I am new to Svelte flow and I can't figure out how can I auth from front-end using svelte-kit and POST action form... from next/react all works perfect, same backend code. This is my +page.server.js

import { fail, redirect } from '@sveltejs/kit';

/** @type {import('./$types').Actions} */
export const actions = {
    default: async ({ fetch, cookies, request }) => {
        const data = await request.formData();
  
        const username = data.get('username');
        const password = data.get('password');

        if (!username || !password) {
            return fail(400, { username, password, missing: true })
        }
  
        const response = await fetch(`${api_url}/login`, { 
            method: "POST",
            headers: { 
                'Content-Type': 'application/json', 
                "WWW-Authenticate": "Bearer",
                'Accept': 'application/json' 
            },
            body: JSON.stringify({username, password})
        })
  
        const json = await response.json();
  
        if (response.status === 200) {
            cookies.set('token', json.access_token, {
                path: '/',
                httpOnly: true,
                sameSite: 'strict',
                maxAge: 60 * 60 * 24 * 1000
            });
            throw redirect(302, "/");
        } else {
            return fail(422, { errors: json });
        }
        
    }
}

I just follow the tutorial in fastapi for 0auth2 authentication, but this errors come only in svelte-kit, where is the mistake? I think the problem is inside fetch call body? Server say the username and password cannot be empty

msg: "field required"
type: "value_error.missing"

my +page.svelte is this:

<script>
import { enhance } from '$app/forms';

/** @type {import('./$types').ActionData} */
export let form;
</script>

<!-- component -->
<div class="w-full min-h-screen bg-cyan-950 text-white flex flex-col sm:justify-center items-center pt-6 sm:pt-0">
    <div class="w-full sm:max-w-md p-5 mx-auto">
      <h2 class="mb-12 text-center text-5xl font-extrabold">Accedi</h2>
      {#if form?.errors}<p class="error">{console.log(form.errors)}</p>{/if}
      <form method="POST" use:enhance>
        <div class="mb-4">
          <label class="block mb-1" for="email">Username</label>
          <input id="username" type="text" name="username" class="text-gray-700 py-2 px-3 border border-gray-300 focus:border-red-300 focus:outline-none focus:ring focus:ring-red-200 focus:ring-opacity-50 rounded-md shadow-sm disabled:bg-gray-100 mt-1 block w-full" />
        </div>
        <div class="mb-4">
          <label class="block mb-1" for="password">Password</label>
          <input id="password" type="password" name="password" class="text-gray-700 py-2 px-3 border border-gray-300 focus:border-red-300 focus:outline-none focus:ring focus:ring-red-200 focus:ring-opacity-50 rounded-md shadow-sm disabled:bg-gray-100 mt-1 block w-full" />
        </div>
        <div class="mt-6 flex items-center justify-between">
          <div class="flex items-center">
            <input id="remember_me" type="checkbox" class="border border-gray-300 text-red-600 shadow-sm focus:border-red-300 focus:ring focus:ring-red-200 focus:ring-opacity-50" />
            <label for="remember_me" class="ml-2 block text-sm leading-5 text-gray-200"> Ricordami </label>
          </div>
        </div>
        <div class="mt-6">
          <button class="w-full inline-flex items-center justify-center px-4 py-2 bg-cyan-600 border border-transparent rounded-md font-semibold capitalize text-white hover:bg-cyan-800 active:bg-red-700 focus:outline-none focus:border-red-700 focus:ring focus:ring-red-200 disabled:opacity-25 transition">Accedi</button>
        </div>
      </form>
    </div>
  </div>

and my fastapi code:

@router.post("/login", response_model=Token, tags=["Auth"])
async def login_for_access_token(
    form_data: Annotated[OAuth2PasswordRequestForm, Depends()]
):
    user = authenticate_user(form_data.username, form_data.password)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect username or password",
            headers={"WWW-Authenticate": "Bearer"},
        )
    access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = create_access_token(
        data={"sub": user.username}, expires_delta=access_token_expires
    )
    return {"access_token": access_token, "token_type": "bearer"}
Pankaspe
  • 91
  • 1
  • 7
  • 1
    Since you didn't include your FastAPI code or the code that works, this is a bit of guessing: but the FastAPI endpoint expects _formdata_, not JSON by default. Since you're submitting your content as JSON, it doesn't find the expected form data (i.e. username and password as form arguments). You probably want to use `FormData` in JavaScript instead. – MatsLindh Apr 02 '23 at 10:55
  • just update the question with fastapi code! – Pankaspe Apr 02 '23 at 11:08
  • 2
    Please have a look at [this answer](https://stackoverflow.com/a/71715353/17865804) as well – Chris Apr 02 '23 at 11:13
  • 2
    Also, you should create the cookie on server side, not client side (using JS), as demonstrated in [this answer](https://stackoverflow.com/a/73137093/17865804), as well as [this answer](https://stackoverflow.com/a/74060795/17865804) and [this answer](https://stackoverflow.com/a/73599289/17865804). Using JS to create cookies is not safe, as one can't create cookies via JS that include the `HttpOnly` flag – Chris Apr 02 '23 at 11:18
  • omg thank you guys, with FormData() all works! – Pankaspe Apr 02 '23 at 12:02

0 Answers0