fix(oidc): session token vs gui token issues

This commit is contained in:
KernelDeimos
2026-02-11 17:10:01 -05:00
parent 5d22ee0517
commit d532b3d47b
5 changed files with 29 additions and 7 deletions
@@ -20,6 +20,7 @@ const APIError = require('../api/APIError');
const config = require('../config');
const { LegacyTokenError } = require('../services/auth/AuthService');
const { Context } = require('../util/context');
const jwt = require('jsonwebtoken');
// The "/whoami" endpoint is a special case where we want to allow
// a legacy token to be used for authentication. The "/whoami"
@@ -47,7 +48,7 @@ const configurable_auth = options => async (req, res, next) => {
const optional = options?.optional;
// Request might already have been authed (PreAuthService)
if ( req.actor ) next();
if ( req.actor ) return next();
// === Getting the Token ===
// This step came from jwt_auth in src/helpers.js
@@ -55,15 +56,18 @@ const configurable_auth = options => async (req, res, next) => {
// auth middleware, it makes more sense to put it here.
let token;
let tokenSource;
// Auth token in body
if ( req.body && req.body.auth_token )
{
token = req.body.auth_token;
tokenSource = 'body';
}
// HTTML Auth header
else if ( req.header && req.header('Authorization') && !req.header('Authorization').startsWith('Basic ') && req.header('Authorization') !== 'Bearer' ) { // Bearer with no space is something office does
token = req.header('Authorization');
token = token.replace('Bearer ', '').trim();
tokenSource = 'header';
if ( token === 'undefined' ) {
APIError.create('unexpected_undefined', null, {
msg: 'The Authorization token cannot be the string "undefined"',
@@ -74,16 +78,19 @@ const configurable_auth = options => async (req, res, next) => {
else if ( req.cookies && req.cookies[config.cookie_name] )
{
token = req.cookies[config.cookie_name];
tokenSource = 'cookie';
}
// Auth token in URL
else if ( req.query && req.query.auth_token )
{
token = req.query.auth_token;
tokenSource = 'query';
}
// Socket
else if ( req.handshake && req.handshake.query && req.handshake.query.auth_token )
{
token = req.handshake.query.auth_token;
tokenSource = 'socket';
}
if ( !token || token.startsWith('Basic ') ) {
@@ -110,6 +117,20 @@ const configurable_auth = options => async (req, res, next) => {
const services = context.get('services');
const svc_auth = services.get('auth');
// Debug: log token source and decoded type before creating Actor (for session_required / hasHttpPowers debugging)
if ( process.env.DEBUG ) {
let decodedForLog;
try {
decodedForLog = jwt.decode(token);
} catch ( _ ) { /* ignore */ }
console.log('decodedForLog?', decodedForLog);
const tokenType = decodedForLog && decodedForLog.t != null ? decodedForLog.t : '(no type or invalid jwt)';
const tokenPreview = typeof token === 'string' && token.length > 20
? `${token.slice(0, 12)}...${token.slice(-8)}`
: '(short)';
console.log(`[configurable_auth] token used for Actor: [${req.url}] source=${tokenSource}, decoded.type=${tokenType}, preview=${tokenPreview}`);
}
let actor;
try {
actor = await svc_auth.authenticate_from_token(token);
+2 -1
View File
@@ -152,10 +152,11 @@ const TabSecurity = {
const password_confirm_promise = new TeePromise();
const try_password = async () => {
const value = $win.find('.password-entry').val();
// Do not send Authorization: user-protected endpoints use session cookie (hasHttpPowers)
const resp = await fetch(`${window.api_origin}/user-protected/disable-2fa`, {
method: 'POST',
credentials: 'include',
headers: {
Authorization: `Bearer ${puter.authToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
+2 -1
View File
@@ -86,10 +86,11 @@ export default {
const password_confirm_promise = new TeePromise();
const try_password = async () => {
const value = password_entry.get('value');
// No Authorization header: user-protected endpoints use session cookie (hasHttpPowers)
const resp = await fetch(`${window.api_origin}/user-protected/disable-2fa`, {
method: 'POST',
credentials: 'include',
headers: {
Authorization: `Bearer ${puter.authToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
+2 -3
View File
@@ -114,13 +114,12 @@ async function UIWindowChangePassword (options) {
$(el_window).find('.form-error-msg').hide();
// Do not send Authorization: user-protected endpoints use session cookie (hasHttpPowers)
$.ajax({
url: `${window.api_origin }/user-protected/change-password`,
type: 'POST',
async: true,
headers: {
'Authorization': `Bearer ${window.auth_token}`,
},
xhrFields: { withCredentials: true },
contentType: 'application/json',
data: JSON.stringify({
password: current_password,
+1 -1
View File
@@ -182,12 +182,12 @@ async function UIWindowChangeUsername (options) {
const new_username = $(el_window).find('.new-username').val();
const body = { new_username };
if ( password !== undefined && password !== '' ) body.password = password;
// Do not send Authorization: user-protected endpoints use session cookie (hasHttpPowers)
return fetch(apiUrl, {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
...(window.auth_token ? { 'Authorization': `Bearer ${window.auth_token}` } : {}),
},
body: JSON.stringify(body),
});