I've just recently started using svelte
and sapper
, and I'm trying to persist a stored session even when a user refreshes the page. (I hope this can be done).
The idea is that a user can sign in, and be redirected to the homepage as an authenticated used. BUT when I hit refresh in my browser, the session is empty and user has to go through sign in process over again.
Any Ideas?
So far I could not find a solution. Below some of the files the are involved in this process.
server.js
import sirv from "sirv";
import polka from "polka";
import compression from "compression";
import * as sapper from "@sapper/server";
import bodyParser from "body-parser";
import session from "express-session";
import sessionFileStore from "session-file-store";
const { PORT, NODE_ENV } = process.env;
const dev = NODE_ENV === "development";
const FileStore = sessionFileStore(session);
polka()
.use(
bodyParser.json(),
session({
secret: "secret",
resave: false,
saveUninitialized: true,
cookie: {
maxAge: 31536000,
},
store: new FileStore({
path: process.env.NOW ? `/tmp/sessions` : `.sessions`,
}),
})
)
.use(
compression({ threshold: 0 }),
sirv("static", { dev }),
sapper.middleware({
session: (req) => ({
user: req.session && req.session.user,
}),
})
)
.listen(PORT, (err) => {
if (err) console.log("error", err);
});
login.svelte
<script context="module">
export async function preload({ params }, { user }) {
if (user) {
this.redirect(302, `/`);
}
}
</script>
<script>
import { goto, stores } from "@sapper/app";
import api from "../api.js";
import Button from "../components/Button.svelte";
import Input from "../components/Input.svelte";
import InputPassword from "../components/InputPassword.svelte";
let errors;
let email;
let password;
let disabled;
const { session } = stores();
const handleSubmit = async () => {
try {
errors = null;
disabled = true;
await api.get("/csrf-cookie");
const authToken = await api.post("/login", { email, password });
api.defaults.headers.common["Authorization"] = `Bearer ${authToken.data}`;
const user = await api.get("/me");
session.set({ user: user.data });
disabled = false;
goto("/");
} catch (e) {
errors = e;
disabled = false;
}
};
</script>
<style>
.login-form {
max-width: 35em;
margin: 5% auto;
padding: 2em;
background: rgba(233, 233, 233, 0.5);
border: 1px solid rgba(151, 151, 151, 0.5);
border-radius: 5px;
}
.form-title {
margin-top: 0;
font-size: 1.2em;
}
.error-block {
color: red;
}
</style>
<svelte:head>
<title>Login</title>
</svelte:head>
<div class="login-form">
<h3 class="form-title">Login</h3>
<form on:submit|preventDefault={handleSubmit}>
<Input placeholder="Username" id="email" bind:value={email} />
<InputPassword placeholder="Password" id="password" bind:value={password} />
<Button {disabled} type="submit">Login</Button>
{#if errors}<span class="error-block">{errors}</span>{/if}
</form>
</div>
index.svelte
<script context="module">
export async function preload({ params }, { user }) {
console.log(user); // undefined
if (!user) {
this.redirect(302, `/login`);
}
}
</script>
<h1>Dashboard</h1>
I'm using Laravel 8 sanctum
for Auth.
Not sure what else I need to provide to get to the bottom of this issue.
It appears as though you lifted most of your code from the sapper realworld project (correct me if I'm wrong), but you forgot to implement a server-side 'api route' to add the freshly logged in user to the session.
In the realworld project, when the user logs in, a POST request is made to the server-side
/auth/login
route, which is served by the following function:What this function does is:
/users/login
endpoint of the realworld project APIuser
object, it stores that object into the server-side sessionConsidering you're obviously NOT using the realworld project API to authenticate against, but your own auth process, what you have to add is a similar server-side route as the one above, but one that will:
Considering the API calls you're using to set the user on the client side in your code, that function would look something like this (saving that file as
/routes/auth/login.js
for example):and the
handleSubmit
method in yourlogin.svelte
file becomes:Note that in your particular case, you'd probably want to store the auth token in the session as well, to avoid having to request a new token every time you want to make an authenticated request to your data API.