HenryCharles Thank you. I’m using the session-sharing plugin, but I’m facing an issue. After logging in with SSO, I call NodeBB APIs directly (not the UI). The express.sid is generated, and I use that express.sid to get the CSRF token. However, when I call the /api/config API, the response always gives uid: 0 instead of the logged-in user’s UID.

balu
Post
-
Unable to Retrieve CSRF Token via /api/config Using express.sid After Keycloak Login -
Unable to Retrieve CSRF Token via /api/config Using express.sid After Keycloak LoginHi,
I have a question regarding the express.sid cookie:After login, the express.sid is generated and stored in the cookies.
I tried using this session ID to fetch the CSRF token by calling /api/config, but it doesn’t seem to work for me.
My goal is:
Successfully retrieve a valid CSRF token.
Use it to create topics or posts via the Write API.
Ensure that once I have this token and session, I can access all the required NodeBB APIs.
Could you please clarify the correct approach to:
Retrieve and use the CSRF token with the express.sid?
Authenticate API requests (like creating topics or posts) when using Keycloak for login instead of NodeBB’s built-in login?
Any guidance or best practices for this integration would be greatly appreciated.
app.post('/api/login', async (req, res) => {
try {
const { username, password } = req.body || {}
if (!username || !password) {
return res.status(400).json({ error: 'Missing username or password' })
}
// 1) Login against Keycloak (Direct Access Grant)
const tokenResponse = await fetchKeycloakTokens({ username, password });// 2) Get user profile to build NodeBB payload const userinfo = await fetchUserInfo({ accessToken: tokenResponse.access_token }); // 3) Build session-sharing JWT for NodeBB // Minimal fields: id (unique), username, email const nodebbPayload = { id: userinfo.sub || userinfo.preferred_username || username, username: userinfo.preferred_username || username, email: userinfo.email || undefined, fullname: userinfo.name || undefined, }; if (!SESSION_SHARING_JWT_SECRET) { return res.status(500).json({ error: 'Server not configured: SESSION_SHARING_JWT_SECRET missing' }); } const signed = await jwt.sign(nodebbPayload, SESSION_SHARING_JWT_SECRET, { expiresIn: '1h' }); const loginRes = await axios.post('http://localhost:4567/api/v3/utilities/login', { username, password }, { headers: { "Content-Type": "application/json", "Authorization": `Bearer ${signed}`, // pass your Bearer token here }, withCredentials: true }); console.log(loginRes, "LOGIN RESPONSE"); // 4) Set cookie for NodeBB domain so it can pick it up const response = await axios.get('http://192.168.60.108:4567/api/config', { withCredentials: true }); const newToken = response?.data?.csrf_token; const cookieOptions = { httpOnly: true, secure: false, sameSite: 'none', path: '/', maxAge: 8 * 60 * 60 * 10000, domain: '192.168.60.108' } res.cookie("token", signed, cookieOptions); res.cookie('csrf_token', newToken, cookieOptions); return res.json({ success: true, message: "login successfully", redirect: NODEBB_BASE_URL, keycloakAccessToken: tokenResponse.access_token });
} catch (err) {
// eslint-disable-next-line no-console
console.error('Login error:', err?.response?.data || err?.message || err);
const status = err?.response?.status || 500
const message = err?.response?.data?.error_description || err?.response?.data?.error || err?.message || 'Unexpected error';
return res.status(status).json({ success: false, error: message });
}});
In the /api/login API, I called the /api/config API, but when I check the /api/config API in Postman using the express.sid generated after login, it never returns the response for that specific user.Thanks in advance!