Reputation: 455
I followed this tutorial to use HTTP-Only cookies in my project: https://maxschmitt.me/posts/next-js-http-only-cookie-auth-tokens
The backend is working fine, I can see the cookie in Postman. But for reference, I'll post the backend code: (note: secure: true is hashed)
router.post('/login', upload.none(), async (req, res, next) => {
const { username, password } = req.body;
if (password != "12345678") {
return res.status(401).send({
message: `You're not authorized!`,
success: false
})
}
const admin_id = "1";
const payload = { id: admin_id, role: "admin" };
const jwt = JWT.sign(payload, secret, { algorithm: 'HS256', expiresIn: "7d" });
res.cookie( "token", jwt, {
httpOnly: true,
// secure: true // only works on https
});
return res.status(200).send({
message: 'Logged in!',
success: true
});
});
The frontend:
The admin login service:
const adminLogin = async (url: string, data: any) => {
const { arg: { username, password } } = data;
let formData = new FormData();
formData.append("username", username);
formData.append("password", password);
try {
const result = await axios.post(url, formData, { headers: { "Content-Type": "multipart/form-data" } });
console.log(result);
return result.data;
} catch (error) {
const err = error as AxiosError;
return err.response!.data;
}
};
The login page: (I'm using SWR package, the onLogin is inside LoginPage component)
const { trigger, isMutating } = useSWRMutation("http://localhost:8000/api/v1/admins/login", adminLogin);
const onLogin = async (data: any) => {
const response = await trigger(data);
if (response.success === true) {
console.log(response);
} else {
setErrorMsg(response.message);
setOpenAlertDialog(true);
}
};
next.config.js:
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true
};
module.exports = {
async rewrites() {
return [{
source: "/api/v1/:path*",
destination: "http://localhost:8000/api/v1/:path*"
}];
}
};
module.exports = nextConfig;
api/[...path].ts:
import httpProxy from "http-proxy";
import Cookies from "cookies";
import url from "url";
const proxy = httpProxy.createProxyServer();
export const config = {
api: {
bodyParser: false
}
};
const main = (req: any, res: any) => {
return new Promise<void>((resolve, reject) => {
const pathname = url.parse(req.url).pathname;
const isLogin = pathname === "/api/login" || pathname === "/api/v1/admins/login";
const cookies = new Cookies(req, res);
const authToken = cookies.get("token");
req.url = req.url.replace(/^\/api/, "");
req.headers.cookie = "";
if (authToken) {
req.headers["token"] = authToken;
}
if (isLogin) {
proxy.once("proxyRes", interceptLoginResponse);
}
proxy.once("error", reject);
proxy.web(req, res, {
target: "http://localhost:8000/api/v1",
autoRewrite: false,
selfHandleResponse: isLogin
});
function interceptLoginResponse(proxyRes: any, req: any, res: any) {
let apiResponseBody = "";
proxyRes.on("data", (chunk: any) => {
apiResponseBody += chunk;
});
proxyRes.on("end", () => {
try {
const { authToken } = JSON.parse(apiResponseBody);
const cookies = new Cookies(req, res);
cookies.set("token", authToken, {
httpOnly: true,
sameSite: "lax",
path: "/"
});
res.status(200).json({ loggedIn: true });
resolve();
} catch (err) {
reject(err);
}
});
}
});
};
export default main;
What am I missing, and how can I cookies from the backend in the login function inside my next.js on my local machine? And what changes will I need to make in my production set up? (I'll be using NginX on my server).
Thanks in advance...
Upvotes: 0
Views: 2198
Reputation: 1
Set 'use client' in the login service file from the frontend.
'use client';
const adminLogin = async (url: string, data: any) => {}
Upvotes: 0
Reputation: 123
You are not telling axios to set the cookies, so it just ignores any cookie it gets
try {
const result = await axios.post(url, formData, { headers: { "Content-Type": "multipart/form-data" },withCredentials: true });
console.log(result);
return result.data;
} catch (error) {
const err = error as AxiosError;
return err.response!.data;
}
Upvotes: 0