Use cookies for authentication as a last resort.

Fixes #335
This commit is contained in:
D. Berge
2025-08-13 16:53:11 +02:00
parent 84510e8dc9
commit 083ee812de
3 changed files with 27 additions and 17 deletions

View File

@@ -29,21 +29,6 @@ async function logout ({ commit, dispatch }) {
commit('setPreferences', {}); commit('setPreferences', {});
} }
function setCookie(context, {name, value, expiry, path}) {
if (!path) path = "/";
if (!value) value = "";
if (name) {
if (expiry) {
document.cookie = `${name}=${value}; expiry=${(new Date(expiry)).toUTCString()}; path=${path}`;
} else {
document.cookie = `${name}=${value}; path=${path}`;
}
} else {
console.warn(`seCookie: You must supply a name`);
}
}
function setCredentials({ state, commit, getters, dispatch, rootState }, { force, token, response } = {}) { function setCredentials({ state, commit, getters, dispatch, rootState }, { force, token, response } = {}) {
try { try {
let tokenValue = token; let tokenValue = token;
@@ -61,6 +46,7 @@ function setCredentials({ state, commit, getters, dispatch, rootState }, { force
const decoded = jwt_decode(tokenValue); const decoded = jwt_decode(tokenValue);
commit('setToken', tokenValue); commit('setToken', tokenValue);
commit('setUser', decoded ? new User(decoded, rootState.api.api) : null); commit('setUser', decoded ? new User(decoded, rootState.api.api) : null);
commit('setCookie', {name: "JWT", value: tokenValue, expires: (decoded.exp??0)*1000});
console.log('Credentials refreshed at', new Date().toISOString()); console.log('Credentials refreshed at', new Date().toISOString());
} else { } else {
@@ -71,6 +57,7 @@ function setCredentials({ state, commit, getters, dispatch, rootState }, { force
if (err.name === 'InvalidTokenError') { if (err.name === 'InvalidTokenError') {
commit('setToken', null); commit('setToken', null);
commit('setUser', null); commit('setUser', null);
commit('clearCookie', "JWT")
} }
} }
dispatch('loadUserPreferences'); dispatch('loadUserPreferences');
@@ -105,7 +92,6 @@ async function loadUserPreferences({ state, commit }) {
export default { export default {
login, login,
logout, logout,
setCookie,
setCredentials, setCredentials,
saveUserPreference, saveUserPreference,
loadUserPreferences loadUserPreferences

View File

@@ -16,4 +16,18 @@ function setPreferences (state, preferences) {
state.preferences = preferences; state.preferences = preferences;
} }
export default { setToken, setUser, setPreferences }; function setCookie (state, opts = {}) {
const name = opts.name ?? "JWT";
const value = opts.value ?? "";
const expires = opts.expires ? (new Date(opts.expires)) : (new Date(0));
const path = opts.path ?? "/";
const sameSite = opts.sameSite ?? "Lax";
document.cookie = `${name}=${value};path=${path};SameSite=${sameSite};expires=${expires.toUTCString()}`;
}
function clearCookie (state, name) {
setCookie(state, {name});
}
export default { setToken, setUser, setPreferences, setCookie, clearCookie };

View File

@@ -166,6 +166,16 @@ async function auth(req, res, next) {
return; return;
} }
// If *all* else fails, check if the user came with a cookie
// (see https://gitlab.com/wgp/dougal/software/-/issues/335)
if (req.cookies.JWT) {
const token = req.cookies.JWT;
delete req.cookies.JWT;
DEBUG("falling back to cookie-based authentication");
req.user = await jwt.checkValidCredentials({jwt: token});
return await auth(req, res, next);
}
next({ status: 401, message: 'Not authorised' }); next({ status: 401, message: 'Not authorised' });
} }