API -> Upload files via custom widget and if the file upload hits the 403 error sometimes

Hello,

We have an api function in hubshare custom widget to link a person object to hub. It worked in POC (on-premise vault), but not in M-Files cloudvault (we have tried using retry to get through the 403 error on multi cloud server authentication problem.

We have tried sending cookies as per the article suggestion support.m-files.com/.../REST-API-and-Multi-Server-Mode-Session-management, but it's still not working (having a lot of 403s).

· Please see the attached screenshots:

Please suggest me any other solution for fix the 403 error's. Thanks!

Regards,

Senthil

  • async function linkPersonToHub(personId, retries = 3, delayMs = 3000) { console.log('Link Attempting to link Person', personId, 'to Hub...'); for (let attempt = 1; attempt <= retries; attempt++) { try { if (attempt > 1) { console.log(`Hourglass flowing sand Retry ${attempt}/${retries} - waiting ${delayMs/1000}s...`); await new Promise(resolve => setTimeout(resolve, delayMs)); } await authenticateWithMFiles(true); if (!authToken) throw new Error('Authentication failed'); const token = authToken; const fetchWithRetry = async (endpoint, opts = {}, maxRetries = 5) => { for (let i = 1; i <= maxRetries; i++) { const resp = await fetch(`${MFILES.baseUrl}${endpoint}`, { ...opts, headers: { 'Content-Type': 'application/json', 'X-Authentication': token, ...opts.headers } }); if (resp.ok || resp.status !== 403) return resp; if (i < maxRetries) { console.log(` ↻ 403 attempt ${i}/${maxRetries}, waiting 500ms...`); await new Promise(r => setTimeout(r, 500)); } } return await fetch(`${MFILES.baseUrl}${endpoint}`, { ...opts, headers: { 'Content-Type': 'application/json', 'X-Authentication': token } }); }; const getResponse = await fetchWithRetry(`objects/${OBJ_TYPE.hub}/${OBJ.hubId}/latest/properties/${PROP.hubAssociatedUsers}`); if (!getResponse.ok) throw new Error(`Failed to get Hub users: ${getResponse.status}`); const propData = await getResponse.json(); const existingUsers = propData?.TypedValue?.Lookups || []; console.log(`Clipboard Found ${existingUsers.length} existing users in Hub`); if (existingUsers.some(u => u.Item === personId)) { console.log('White check mark Person already linked to Hub'); return true; } const updatedUsers = [...existingUsers, { Item: personId }]; const checkoutResponse = await fetchWithRetry(`objects/${OBJ_TYPE.hub}/${OBJ.hubId}/latest/checkedout`, { method: 'PUT', body: JSON.stringify({ Value: true }) }); if (!checkoutResponse.ok) throw new Error(`Checkout failed: ${checkoutResponse.status}`); console.log('Lock Object checked out'); try { const putResponse = await fetchWithRetry(`objects/${OBJ_TYPE.hub}/${OBJ.hubId}/latest/properties/${PROP.hubAssociatedUsers}`, { method: 'PUT', body: JSON.stringify({ PropertyDef: PROP.hubAssociatedUsers, TypedValue: { DataType: 10, Lookups: updatedUsers } }) }); if (!putResponse.ok) throw new Error(`Update failed: ${putResponse.status}`); console.log('Pencil Property updated'); const checkinResponse = await fetchWithRetry(`objects/${OBJ_TYPE.hub}/${OBJ.hubId}/latest/checkedout`, { method: 'PUT', body: JSON.stringify({ Value: false }) }); if (!checkinResponse.ok) { console.warn('Warning️ Checkin failed, trying undo...'); await fetchWithRetry(`objects/${OBJ_TYPE.hub}/${OBJ.hubId}/latest/checkedout`, { method: 'PUT', body: JSON.stringify({ Value: 0 }) }); const verifyResponse = await fetchWithRetry(`objects/${OBJ_TYPE.hub}/${OBJ.hubId}/latest/properties/${PROP.hubAssociatedUsers}`); if (verifyResponse.ok) { const verifyData = await verifyResponse.json(); if (verifyData?.TypedValue?.Lookups?.some(u => u.Item === personId)) { console.log(`White check mark Person ${personId} linked to Hub (verified after undo)`); return true; } } throw new Error('Update did not persist after undo'); } console.log(`White check mark Person ${personId} linked to Hub successfully`); return true; } catch (updateError) { console.warn('Warning️ Error during update, undoing checkout...'); await fetchWithRetry(`objects/${OBJ_TYPE.hub}/${OBJ.hubId}/latest/checkedout`, { method: 'PUT', body: JSON.stringify({ Value: 0 }) }); throw updateError; } } catch (error) { console.warn(`Warning️ Attempt ${attempt}/${retries} failed:`, error.message); if (attempt === retries) { console.warn('Warning️ Could not link Person to Hub after all retries'); return false; } } } return false; } async function mfilesRequest(endpoint, options = {}) { if (!authToken) await authenticateWithMFiles(false); if (!authToken) throw new Error('No auth token available'); let response; let retries = 0; while (retries < 5) { response = await fetch(`${MFILES.baseUrl}${endpoint}`, { ...options, headers: { 'Content-Type': 'application/json', 'X-Authentication': authToken, ...options.headers } }); if (response.ok || response.status !== 403) { return response; } retries++; if (retries < 5) { console.log(`Arrows counterclockwise 403 on attempt ${retries}/5 - retrying same token in 500ms...`); await new Promise(r => setTimeout(r, 500)); } } // After 5 retries with same token, try fresh token once console.log('Arrows counterclockwise 5 retries failed, getting fresh token...'); await authenticateWithMFiles(true); if (!authToken) throw new Error('Re-authentication failed'); return await fetch(`${MFILES.baseUrl}${endpoint}`, { ...options, headers: { 'Content-Type': 'application/json', 'X-Authentication': authToken, ...options.headers } }); } async function authenticateWithMFiles(forceRefresh = false) { console.log('Closed lock with key authenticateWithMFiles called, forceRefresh:', forceRefresh); if (!forceRefresh && authToken && tokenExpiry && Date.now() < tokenExpiry) { console.log('White check mark Using cached token'); return authToken; } authToken = null; tokenExpiry = null; try { console.log('Key Getting auth token...'); const serverResponse = await fetch(`${MFILES.baseUrl}server/authenticationtokens`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ Username: MFILES.username, Password: MFILES.password, VaultGuid: MFILES.vaultGuid }) }); if (!serverResponse.ok) throw new Error(`Server auth failed: ${serverResponse.status}`); const serverAuth = await serverResponse.json(); authToken = serverAuth.Value; console.log('White check mark Token obtained'); tokenExpiry = Date.now() + (25 * 60 * 1000); console.log('Hourglass flowing sand Waiting for token propagation...'); await new Promise(resolve => setTimeout(resolve, 1500)); console.log('White check mark Authentication complete'); return authToken; } catch (error) { console.error('X Authentication error:', error); authToken = null; tokenExpiry = null; return null; } }

  • I've updated the full http response. Could you please check and share your inputs.

  • Firstly: this is a peer-to-peer support forum.  If you post a message or a reply then there is no SLA on when you get a response.  It is not good etiquette to chance for one immediately after you post something; someone will reply when they get a chance to do so.  If you need an SLA then you can, of course, contact your partner manager or account manager for alternate, paid, consultancy options.

    Secondly: I don't see what I asked for.

    Thirdly: I will now be away from the office for a couple of days, so please do not have any expectations that I will - personally - respond to any further messages for the next week or so.  If you can provide answers to the actual question then hopefully someone else can help.