H
Hono5mo ago
Chi Hao

unable to retrieve cookie value

// index.ts
import { Hono } from 'hono';
import { getCookie, setCookie} from 'hono/cookie';
import CryptoJS from 'crypto-js';

const app = new Hono();

app.get('/csrf', (c) => {
setCookie(c, 'X-CSRF-Token', 'abc');
const testget = getCookie(c, 'X-CSRF-Token');
console.log('test get: ', testget);

const allCookies = getCookie(c);
console.log('allCookies : ', allCookies);

return c.text(csrfToken);
});

export default app;
// index.ts
import { Hono } from 'hono';
import { getCookie, setCookie} from 'hono/cookie';
import CryptoJS from 'crypto-js';

const app = new Hono();

app.get('/csrf', (c) => {
setCookie(c, 'X-CSRF-Token', 'abc');
const testget = getCookie(c, 'X-CSRF-Token');
console.log('test get: ', testget);

const allCookies = getCookie(c);
console.log('allCookies : ', allCookies);

return c.text(csrfToken);
});

export default app;
this is the log
test get: undefined
allCookies : {}
[wrangler:inf] GET /csrf 200 OK (8ms)
test get: undefined
allCookies : {}
[wrangler:inf] GET /csrf 200 OK (8ms)
25 Replies
Nico
Nico5mo ago
Can you test this from a browser or client? The cookies might not be set inside the route yet
Aditya Mathur
Aditya Mathur5mo ago
Okay, here is the thing, setCookie function sends a http header Set-Cookie to the browser asking it set the cookie for the user. So the cookie hasn’t been setted yet! On the next request you will get the cookie value using the getCookie function.
Chi Hao
Chi Hao5mo ago
this is my hono backend
app.get('/csrf', (c) => {
setCookie(c, 'X-CSRF-Token', 'abc');
return c.text('abc');
});

app.get("/testcsrf", (c) => {
const csrfToken = getCookie(c, "X-CSRF-Token");
console.log("csrf cookie: ", csrfToken);
// csrf cookie: undefined
const headerCsrfToken = c.req.header("X-CSRF-Token");
console.log("headerCsrfToken: ", headerCsrfToken);
// headerCsrfToken: abc

if (csrfToken !== headerCsrfToken) {
return c.json({ data: null, message: "Invalid CSRF Token" }, 403);
}

return c.json({ data: null, message: "ok" }, 200);
});
app.get('/csrf', (c) => {
setCookie(c, 'X-CSRF-Token', 'abc');
return c.text('abc');
});

app.get("/testcsrf", (c) => {
const csrfToken = getCookie(c, "X-CSRF-Token");
console.log("csrf cookie: ", csrfToken);
// csrf cookie: undefined
const headerCsrfToken = c.req.header("X-CSRF-Token");
console.log("headerCsrfToken: ", headerCsrfToken);
// headerCsrfToken: abc

if (csrfToken !== headerCsrfToken) {
return c.json({ data: null, message: "Invalid CSRF Token" }, 403);
}

return c.json({ data: null, message: "ok" }, 200);
});
this is my frontend astro
// api.ts
async getCSRFToken(): Promise<any> {
try {
const response = await fetch(this.backend_url + "/csrf");
console.log(response.headers);
return await response.text();
} catch (error: any) {
throw new Error("error in api.getCSRFToken: " + error);
}
}

async checkCSRFToken(data: any): Promise<any> {
try {
const token = await this.getCSRFToken();
console.log("frotendCSRFToken : ", token);
// log: frotendCSRFToken : 'abc'

const response = await fetch(this.backend_url + "/testcsrf", {
headers: {
"X-CSRF-Token": token,
},
});
return await this.sanitizeDataFetch(response);
} catch (error: any) {
throw new Error("error in api.checkcsrfpost: " + error.message);
}
}
// api.ts
async getCSRFToken(): Promise<any> {
try {
const response = await fetch(this.backend_url + "/csrf");
console.log(response.headers);
return await response.text();
} catch (error: any) {
throw new Error("error in api.getCSRFToken: " + error);
}
}

async checkCSRFToken(data: any): Promise<any> {
try {
const token = await this.getCSRFToken();
console.log("frotendCSRFToken : ", token);
// log: frotendCSRFToken : 'abc'

const response = await fetch(this.backend_url + "/testcsrf", {
headers: {
"X-CSRF-Token": token,
},
});
return await this.sanitizeDataFetch(response);
} catch (error: any) {
throw new Error("error in api.checkcsrfpost: " + error.message);
}
}
// testcsrf.astro
---
import { api, widget } from "@/utils";

try {
const { ok, errorMessage, data } = await api.checkCSRFToken({
field1: "value1",
field2: "value2",
});

if (!ok) {
widget.alertError("custommessage", errorMessage);
}
} catch (error) {
throw new Error("Error in functionX: " + error);
}
---
// testcsrf.astro
---
import { api, widget } from "@/utils";

try {
const { ok, errorMessage, data } = await api.checkCSRFToken({
field1: "value1",
field2: "value2",
});

if (!ok) {
widget.alertError("custommessage", errorMessage);
}
} catch (error) {
throw new Error("Error in functionX: " + error);
}
---
this is the log for console.log(response.headers);
console.log(response.headers);
/* log
Headers {
Symbol(headers list): HeadersList {
cookies: [ 'X-CSRF-Token=abc; Path=/' ],
Symbol(headers map): Map {
transfer-encoding: { name: 'Transfer-Encoding', value: 'chunked' },
content-type: { name: 'Content-Type', value: 'text/plain; charset=UTF-8' },
content-encoding: { name: 'Content-Encoding', value: 'gzip' },
set-cookie: { name: 'Set-Cookie', value: 'X-CSRF-Token=abc; Path=/' },
vary: { name: 'Vary', value: 'Origin' },
access-control-allow-credentials: { name: 'access-control-allow-credentials', value: 'true' },
access-control-expose-headers: {
name: 'access-control-expose-headers',
value: 'Content-Length,X-Kuma-Revision,Origin'
}
},
Symbol(headers map sorted): null
},
Symbol(guard): 'immutable',
Symbol(realm): null
}
*/
console.log(response.headers);
/* log
Headers {
Symbol(headers list): HeadersList {
cookies: [ 'X-CSRF-Token=abc; Path=/' ],
Symbol(headers map): Map {
transfer-encoding: { name: 'Transfer-Encoding', value: 'chunked' },
content-type: { name: 'Content-Type', value: 'text/plain; charset=UTF-8' },
content-encoding: { name: 'Content-Encoding', value: 'gzip' },
set-cookie: { name: 'Set-Cookie', value: 'X-CSRF-Token=abc; Path=/' },
vary: { name: 'Vary', value: 'Origin' },
access-control-allow-credentials: { name: 'access-control-allow-credentials', value: 'true' },
access-control-expose-headers: {
name: 'access-control-expose-headers',
value: 'Content-Length,X-Kuma-Revision,Origin'
}
},
Symbol(headers map sorted): null
},
Symbol(guard): 'immutable',
Symbol(realm): null
}
*/
however the cookie is still not in the list of cookies at http://localhost4321
Chi Hao
Chi Hao5mo ago
if i go to this link in my backend url in my browser http://127.0.0.1:8787/csrf, it will set the cookie at http://127.O.O.1:8787
No description
Chi Hao
Chi Hao5mo ago
however it's not setting the cookie at http://localhost:4321/, so i wonder if it cannot set cookie at different domain
Nico
Nico5mo ago
Yeah cookie don’t set cross domain and a different port is considered cross domain in this scenario I set the cookie on my frontend on login and send it as a bearer token with each request What’s frontend framework are you using?
Chi Hao
Chi Hao5mo ago
astro
Nico
Nico5mo ago
What library I mean like svelte, react, vue
Chi Hao
Chi Hao5mo ago
react, but currently im running the code at astro server side even though astro can have it's own server side code but im just maintaining it so all the api are in hono
Nico
Nico5mo ago
Do you want to run Hono and Astro together as one? It may be possible I’d have to look into Astro server side a little more That would solve your problem So that’s what I do with SvelteKit. Even though it can do server side I sent all the routes to Hono running inside svelte kit Either way to solve your issue you would need to use the same domain which includes subdomain. So you can have api.yoursite it will still not allow cookies to be set automatically And it appears Astro is almost identical to SvelteKit and server side so you can run them both together as well
Chi Hao
Chi Hao5mo ago
I may not understand your suggestion clearly. my astro is at http://localhost:4321 and my backend is at http://127.0.0.1:8787. Do I call my api in my astro server side and use the astro server side to set the cookie value which I receive from my backend response?
Aditya Mathur
Aditya Mathur5mo ago
You can store the cookie across sub domain of a single domain
Nico
Nico5mo ago
I’ve had issues each time I try it so I may be wrong there
Chi Hao
Chi Hao5mo ago
since my astro is being deployed to cloudflare pages (mypage.com) and hono deployed to cloudflare worker (maybe i can set it to backend.mypage.com) however in local development, i dont think I can do something like subdomain?
Aditya Mathur
Aditya Mathur5mo ago
localhost and 127.0.0.1 is acting like 2 different domain. You can share cookies between different domains. When you send a request to your api, the browser send the cookies connected to your api domain and also of your base domain. That's all, not of all the domains or subdomain which are not relevant Just try it on localhost:8787, that should help you out Yeah, it's a security issue too at times, and a bit trick to setup also 😅 . Messed up a lot on this but now I know
Chi Hao
Chi Hao5mo ago
oh I didnt know you can do this, could you guide me on how I can adjust my backend to run on localhost:8787 instead of 127.0.0.1? because currently the domain is being automatically set
Aditya Mathur
Aditya Mathur5mo ago
127.0.0.1 and localhost are the same things, just the naming is different. Try sending your requests to localhost:8787, it should work like normal. When we say localhost:8787 it means that it can only run on your computers network, nobody on your WIFI can access this app but when we say 127.0.0.1, it means your computer and anyone on the network can access this, so like your friend or colleagues which want to try out your apis
Chi Hao
Chi Hao5mo ago
in my frontend, i can call http://127.0.0.1:8787 but why I cant call http://localhost:8787 ? however i can go to my browser at http://localhost:8787, and it will show me the response text. Does this mean i need to reconfigure my windows system to map localhost to 127.0.0.1 ? this is my backend terminal when I run npm run dev
> wrangler dev

⛅️ wrangler 3.57.1 (update available 3.59.0)
-------------------------------------------------------
Your worker has access to the following bindings:
- Vars:
Starting local server...
[wrangler:inf] Ready on http://127.0.0.1:8787
[wrangler:inf] GET / 200 OK (56ms)
[wrangler:inf] GET /favicon.ico 404 Not Found (8ms)
[wrangler:inf] GET /csrf 200 OK (8ms)
> wrangler dev

⛅️ wrangler 3.57.1 (update available 3.59.0)
-------------------------------------------------------
Your worker has access to the following bindings:
- Vars:
Starting local server...
[wrangler:inf] Ready on http://127.0.0.1:8787
[wrangler:inf] GET / 200 OK (56ms)
[wrangler:inf] GET /favicon.ico 404 Not Found (8ms)
[wrangler:inf] GET /csrf 200 OK (8ms)
Aditya Mathur
Aditya Mathur5mo ago
What is the url of your frontend? 127.0.0.1 or localhost?
Chi Hao
Chi Hao5mo ago
localhost:4321
Chi Hao
Chi Hao5mo ago
Stack Overflow
localhost doesn't point to 127.0.0.1
when I ping localhost, the answer is: alsotang@alsotang-laptop:~$ ping localhost PING localhost (61.139.8.100) 56(84) bytes of data. but the hosts file has a record that 127.0.0.1<feff> loc...
Chi Hao
Chi Hao5mo ago
for some reason this doesnt work, even though i can go to localhost:8787 on my browser, but i cant fetch from it. so i've decided to run my frontend on http://127.0.0.1:4321/testcsrf and my backend on http://127.0.0.1:8787 the route to set cookie is at http://127.0.0.1:8787/csrf, so i call this url in my frontend and I wonder why it doesnt set the cookie at http://127.0.0.1:4321. if I go to this url in my browser http://127.0.0.1:8787/csrf, it does set the cookie and at it shows domain 127.0.0.1. this is how I'm fetching in my frontend but the cookie is not set
const response = await fetch("http://127.0.0.1:8787/csrf", {
credentials: "include",
});
const response = await fetch("http://127.0.0.1:8787/csrf", {
credentials: "include",
});
I thought both frontend and backend are in the same domain now but the cookie is still not set
jep
jep2mo ago
did you figure this out?
Aditya Mathur
Aditya Mathur2mo ago
Can you share the code where you are setting the cookie?
Chi Hao
Chi Hao2mo ago
hi that was very long time ago🤣, my solution was this. If you are using a front end framework like Astro, NextJS, Nuxt and etc, just set the cookie via the server side (API endpoints, server actions) instead of using hono to set the cookie. If you really want your hono backend to set cookie in your front end which is on another domain, just make sure to configure both to be on the same domain like localhost (but I did'nt managed to do this). Since I'm using Astro, the flow was like this Astro client side (call /api/csrf) --> astro server side (/api/csrf sets csrf cookie and return csrf token value) --> astro client side (call /api/backend with csrf token in header) --> astro server side (/api/backend checks whether csrf token header and cookie value is same then proceed to call hono in server side). So, actually the server side or api endpoint will be acting like a proxy server.
Want results from more Discord servers?
Add your server