Refactor authentication handling and improve API client security
- Updated OAuth endpoints for Challonge and Discord in platforms configuration. - Implemented session and CSRF cookie initialization in main application entry. - Enhanced Challonge API client to avoid sending sensitive API keys from the browser. - Modified tournament querying to handle new state definitions and improved error handling. - Updated UI components to reflect server-side storage of authentication tokens. - Improved user experience in API Key Manager and Authentication Hub with clearer messaging. - Refactored client credentials management to support asynchronous operations. - Adjusted API client tests to validate new request configurations. - Updated Vite configuration to support session and CSRF handling through proxies.
This commit is contained in:
@@ -50,14 +50,10 @@ export const ScopeType = {
|
||||
* @returns {Object} API client with methods
|
||||
*/
|
||||
export function createChallongeV2Client(auth, options = {}) {
|
||||
const { token, type = AuthType.API_KEY } = auth;
|
||||
const { token, type = AuthType.API_KEY } = auth || {};
|
||||
const { communityId: defaultCommunityId, debug = false } = options;
|
||||
const baseURL = getBaseURL();
|
||||
|
||||
if (!token) {
|
||||
throw new Error('Authentication token is required');
|
||||
}
|
||||
|
||||
// Request tracking for debug mode
|
||||
let requestCount = 0;
|
||||
|
||||
@@ -109,16 +105,15 @@ export function createChallongeV2Client(auth, options = {}) {
|
||||
...headers
|
||||
};
|
||||
|
||||
// Add authorization header
|
||||
if (type === AuthType.OAUTH) {
|
||||
requestHeaders['Authorization'] = `Bearer ${token}`;
|
||||
} else {
|
||||
requestHeaders['Authorization'] = token;
|
||||
}
|
||||
// No-split-brain: never send Challonge tokens from the browser.
|
||||
// Backend proxy derives auth from the per-session SID cookie and the Authorization-Type hint.
|
||||
// (Token is intentionally ignored here.)
|
||||
|
||||
const fetchOptions = {
|
||||
method,
|
||||
headers: requestHeaders
|
||||
headers: requestHeaders,
|
||||
credentials: 'include',
|
||||
cache: 'no-store'
|
||||
};
|
||||
|
||||
if (body && method !== 'GET') {
|
||||
@@ -149,16 +144,29 @@ export function createChallongeV2Client(auth, options = {}) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Parse response body (prefer JSON when declared)
|
||||
const contentType = response.headers.get('content-type') || '';
|
||||
let data;
|
||||
try {
|
||||
data = await response.json();
|
||||
if (contentType.includes('application/json')) {
|
||||
data = await response.json();
|
||||
} else {
|
||||
const text = await response.text();
|
||||
// Best-effort: if it's actually JSON but wrong content-type, parse it.
|
||||
data = text;
|
||||
if (text && (text.startsWith('{') || text.startsWith('['))) {
|
||||
try {
|
||||
data = JSON.parse(text);
|
||||
} catch {
|
||||
// keep as text
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (parseError) {
|
||||
// If JSON parsing fails, create an error with the status
|
||||
if (debug)
|
||||
if (debug) {
|
||||
console.error('[Challonge v2.1 JSON Parse Error]', parseError);
|
||||
const error = new Error(
|
||||
`HTTP ${response.status}: Failed to parse response`
|
||||
);
|
||||
}
|
||||
const error = new Error(`HTTP ${response.status}: Failed to parse response`);
|
||||
error.status = response.status;
|
||||
throw error;
|
||||
}
|
||||
@@ -186,14 +194,24 @@ export function createChallongeV2Client(auth, options = {}) {
|
||||
.join('\n');
|
||||
|
||||
const error = new Error(errorMessage);
|
||||
error.status = response.status;
|
||||
error.errors = errorDetails;
|
||||
error.response = data;
|
||||
throw error;
|
||||
}
|
||||
// Handle non-JSON:API error format
|
||||
const error = new Error(
|
||||
`HTTP ${response.status}: ${data.message || response.statusText}`
|
||||
);
|
||||
const messageFromBody =
|
||||
typeof data === 'string'
|
||||
? data
|
||||
: data?.error || data?.message || response.statusText;
|
||||
|
||||
const fallbackMessage = response.statusText || 'Request failed';
|
||||
const finalMessage =
|
||||
typeof messageFromBody === 'string' && messageFromBody.trim().length === 0
|
||||
? fallbackMessage
|
||||
: messageFromBody || fallbackMessage;
|
||||
|
||||
const error = new Error(`HTTP ${response.status}: ${finalMessage}`);
|
||||
error.status = response.status;
|
||||
error.response = data;
|
||||
throw error;
|
||||
|
||||
Reference in New Issue
Block a user