fix(oidc): http-only cookie sync for switch user

This commit is contained in:
KernelDeimos
2026-02-19 16:21:41 -05:00
parent b5a3323811
commit 42d3f9e816
2 changed files with 49 additions and 0 deletions
@@ -714,6 +714,34 @@ class AuthService extends BaseService {
return res.json({ token: gui_token });
},
}).attach(app);
// Sync HTTP-only session cookie to the user implied by the request's auth token.
// Used when switching users in the UI: client sends Authorization with the new user's
// GUI token; we set the session cookie so cookie-based (e.g. user-protected) requests match.
Endpoint({
route: '/session/sync-cookie',
methods: ['GET'],
mw: [configurable_auth()],
handler: async (req, res) => {
if ( ! req.user ) {
return res.status(401).end();
}
const actor = Context.get('actor');
if ( !(actor.type instanceof UserActorType) || !actor.type.session ) {
return res.status(400).end();
}
const session_token = svc_auth.create_session_token_for_session(
actor.type.user,
actor.type.session,
);
res.cookie(config.cookie_name, session_token, {
sameSite: 'none',
secure: true,
httpOnly: true,
});
return res.status(204).end();
},
}).attach(app);
}
}
+21
View File
@@ -461,6 +461,27 @@ window.update_auth_data = async (auth_token, user, api_origin) => {
window.auth_token = auth_token;
localStorage.setItem('auth_token', auth_token);
// Set http-only session cookie when user is changing.
// This ensures user-protected endpoints, which only refer to the http-only cookie,
// act on the intended user.
// Only the server can set this cookie, so we call the `/session/sync-cookie` endpoint.
const userChanging = !window.user || window.user.uuid !== user.uuid;
if ( userChanging && auth_token && (window.gui_origin || window.location?.origin) ) {
try {
const origin = window.gui_origin || window.location.origin;
await fetch(`${origin}/session/sync-cookie`, {
method: 'GET',
credentials: 'include',
headers: { Authorization: `Bearer ${auth_token}` },
});
} catch (e) {
console.error('Failed to sync session cookie:', e);
await UIAlert({
message: `Failed to sync session cookie: ${ e.message}`,
});
}
}
if ( api_origin ) {
window.api_origin = api_origin;
localStorage.setItem('api_origin', api_origin);