From 234d64e3c03b8829c1acaf43530dd5c1159b32d4 Mon Sep 17 00:00:00 2001 From: d-klotz Date: Fri, 13 Feb 2026 12:03:32 -0300 Subject: [PATCH 1/5] fix(logging): enhance debug logging for auth headers --- packages/core/handlers/app-handler-helpers.js | 10 +++++++++- .../core/user/use-cases/authenticate-user.js | 18 ++++++++++++++++++ .../use-cases/get-user-from-x-frigg-headers.js | 9 +++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/packages/core/handlers/app-handler-helpers.js b/packages/core/handlers/app-handler-helpers.js index cde6bc7d1..83b8927a9 100644 --- a/packages/core/handlers/app-handler-helpers.js +++ b/packages/core/handlers/app-handler-helpers.js @@ -32,7 +32,15 @@ const createApp = (applyMiddleware) => { flushDebugLog(boomError); res.status(statusCode).json({ error: 'Internal Server Error' }); } else { - console.warn(`[Frigg] ${req.method} ${req.path} -> ${statusCode}: ${err.message}`); + const authHeaders = Object.entries(req.headers) + .filter(([key]) => key.startsWith('x-frigg') || key === 'authorization') + .reduce((acc, [key, value]) => { + acc[key] = key === 'x-frigg-api-key' ? `${value.substring(0, 4)}...` + : key === 'authorization' ? `${value.split(' ')[0]} ...` + : value; + return acc; + }, {}); + console.warn(`[Frigg] ${req.method} ${req.path} -> ${statusCode}: ${err.message}`, JSON.stringify({ authHeaders })); res.status(statusCode).json({ error: err.message }); } }); diff --git a/packages/core/user/use-cases/authenticate-user.js b/packages/core/user/use-cases/authenticate-user.js index c7dee175e..973fc314d 100644 --- a/packages/core/user/use-cases/authenticate-user.js +++ b/packages/core/user/use-cases/authenticate-user.js @@ -52,10 +52,28 @@ class AuthenticateUser { const appOrgId = req.headers['x-frigg-apporgid']; let user = null; + // DEBUG: Log all auth-related headers + const xFriggHeaders = Object.entries(req.headers) + .filter(([key]) => key.startsWith('x-frigg')) + .reduce((acc, [key, value]) => { + acc[key] = key === 'x-frigg-api-key' ? `${value.substring(0, 4)}...` : value; + return acc; + }, {}); + const hasAuthorization = !!req.headers.authorization; + console.log(`[Frigg][DEBUG] ${req.method} ${req.path} - Auth headers:`, JSON.stringify({ + xFriggHeaders, + hasAuthorization, + authorizationType: hasAuthorization ? req.headers.authorization.split(' ')[0] : null, + appUserId: appUserId || '(missing)', + appOrgId: appOrgId || '(missing)', + enabledAuthModes: authModes, + })); + // Priority 1: Shared Secret (backend-to-backend with API key) if (authModes.sharedSecret !== false) { const apiKey = req.headers['x-frigg-api-key']; if (apiKey) { + console.log(`[Frigg][DEBUG] Taking shared secret auth path`); // Validate the API key (authentication) await this.authenticateWithSharedSecret.execute(apiKey); // Get user from x-frigg headers (authorization) diff --git a/packages/core/user/use-cases/get-user-from-x-frigg-headers.js b/packages/core/user/use-cases/get-user-from-x-frigg-headers.js index 840028571..399865691 100644 --- a/packages/core/user/use-cases/get-user-from-x-frigg-headers.js +++ b/packages/core/user/use-cases/get-user-from-x-frigg-headers.js @@ -28,6 +28,15 @@ class GetUserFromXFriggHeaders { * @throws {Boom} 400 Bad Request if neither ID is provided or if both IDs are provided but belong to different users. */ async execute(appUserId, appOrgId) { + console.log(`[Frigg][DEBUG] getUserFromXFriggHeaders called with:`, JSON.stringify({ + appUserId: appUserId || '(falsy)', + appOrgId: appOrgId || '(falsy)', + appUserIdType: typeof appUserId, + appOrgIdType: typeof appOrgId, + individualUserRequired: this.userConfig.individualUserRequired, + organizationUserRequired: this.userConfig.organizationUserRequired, + })); + // At least one header must be provided if (!appUserId && !appOrgId) { throw Boom.badRequest( From 9bf0855a3a4b1d60c3fbf617b171a8d9966e9dfb Mon Sep 17 00:00:00 2001 From: d-klotz Date: Fri, 13 Feb 2026 12:09:21 -0300 Subject: [PATCH 2/5] fix(auth): enhance logging for all request headers --- .../core/user/use-cases/authenticate-user.js | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/packages/core/user/use-cases/authenticate-user.js b/packages/core/user/use-cases/authenticate-user.js index 973fc314d..a42b8fbde 100644 --- a/packages/core/user/use-cases/authenticate-user.js +++ b/packages/core/user/use-cases/authenticate-user.js @@ -52,20 +52,19 @@ class AuthenticateUser { const appOrgId = req.headers['x-frigg-apporgid']; let user = null; - // DEBUG: Log all auth-related headers - const xFriggHeaders = Object.entries(req.headers) - .filter(([key]) => key.startsWith('x-frigg')) - .reduce((acc, [key, value]) => { - acc[key] = key === 'x-frigg-api-key' ? `${value.substring(0, 4)}...` : value; - return acc; - }, {}); - const hasAuthorization = !!req.headers.authorization; - console.log(`[Frigg][DEBUG] ${req.method} ${req.path} - Auth headers:`, JSON.stringify({ - xFriggHeaders, - hasAuthorization, - authorizationType: hasAuthorization ? req.headers.authorization.split(' ')[0] : null, - appUserId: appUserId || '(missing)', - appOrgId: appOrgId || '(missing)', + // DEBUG: Log ALL request headers to catch misspellings + const allHeaders = Object.entries(req.headers).reduce((acc, [key, value]) => { + if (key === 'x-frigg-api-key' || key === 'authorization') { + acc[key] = `${String(value).substring(0, 6)}...(redacted)`; + } else { + acc[key] = value; + } + return acc; + }, {}); + console.log(`[Frigg][DEBUG] ${req.method} ${req.path} - ALL headers:`, JSON.stringify(allHeaders)); + console.log(`[Frigg][DEBUG] Parsed auth values:`, JSON.stringify({ + appUserId: appUserId ?? '(undefined)', + appOrgId: appOrgId ?? '(undefined)', enabledAuthModes: authModes, })); From c5ef83fae0876e66e46a74a0950750c742f0ceae Mon Sep 17 00:00:00 2001 From: d-klotz Date: Fri, 13 Feb 2026 12:38:10 -0300 Subject: [PATCH 3/5] fix(logging): redact sensitive headers in error logs --- packages/core/handlers/app-handler-helpers.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/packages/core/handlers/app-handler-helpers.js b/packages/core/handlers/app-handler-helpers.js index 83b8927a9..0dffd72d4 100644 --- a/packages/core/handlers/app-handler-helpers.js +++ b/packages/core/handlers/app-handler-helpers.js @@ -32,15 +32,19 @@ const createApp = (applyMiddleware) => { flushDebugLog(boomError); res.status(statusCode).json({ error: 'Internal Server Error' }); } else { - const authHeaders = Object.entries(req.headers) - .filter(([key]) => key.startsWith('x-frigg') || key === 'authorization') - .reduce((acc, [key, value]) => { - acc[key] = key === 'x-frigg-api-key' ? `${value.substring(0, 4)}...` - : key === 'authorization' ? `${value.split(' ')[0]} ...` - : value; + try { + const allHeaders = Object.entries(req.headers).reduce((acc, [key, value]) => { + if (key === 'x-frigg-api-key' || key === 'authorization') { + acc[key] = `${String(value).substring(0, 6)}...(redacted)`; + } else { + acc[key] = value; + } return acc; }, {}); - console.warn(`[Frigg] ${req.method} ${req.path} -> ${statusCode}: ${err.message}`, JSON.stringify({ authHeaders })); + console.warn(`[Frigg] ${req.method} ${req.path} -> ${statusCode}: ${err.message}`, JSON.stringify({ headers: allHeaders })); + } catch (logErr) { + console.warn(`[Frigg] ${req.method} ${req.path} -> ${statusCode}: ${err.message} (header logging failed: ${logErr.message})`); + } res.status(statusCode).json({ error: err.message }); } }); From 9264ad8042a5d4d7bb45dd30d5c7a2d39583c66c Mon Sep 17 00:00:00 2001 From: d-klotz Date: Fri, 13 Feb 2026 13:01:41 -0300 Subject: [PATCH 4/5] refactor(logging): remove redundant header logging --- packages/core/handlers/app-handler-helpers.js | 14 +------ .../core/user/use-cases/authenticate-user.js | 40 ++++++++----------- .../get-user-from-x-frigg-headers.js | 9 ----- 3 files changed, 17 insertions(+), 46 deletions(-) diff --git a/packages/core/handlers/app-handler-helpers.js b/packages/core/handlers/app-handler-helpers.js index 0dffd72d4..cde6bc7d1 100644 --- a/packages/core/handlers/app-handler-helpers.js +++ b/packages/core/handlers/app-handler-helpers.js @@ -32,19 +32,7 @@ const createApp = (applyMiddleware) => { flushDebugLog(boomError); res.status(statusCode).json({ error: 'Internal Server Error' }); } else { - try { - const allHeaders = Object.entries(req.headers).reduce((acc, [key, value]) => { - if (key === 'x-frigg-api-key' || key === 'authorization') { - acc[key] = `${String(value).substring(0, 6)}...(redacted)`; - } else { - acc[key] = value; - } - return acc; - }, {}); - console.warn(`[Frigg] ${req.method} ${req.path} -> ${statusCode}: ${err.message}`, JSON.stringify({ headers: allHeaders })); - } catch (logErr) { - console.warn(`[Frigg] ${req.method} ${req.path} -> ${statusCode}: ${err.message} (header logging failed: ${logErr.message})`); - } + console.warn(`[Frigg] ${req.method} ${req.path} -> ${statusCode}: ${err.message}`); res.status(statusCode).json({ error: err.message }); } }); diff --git a/packages/core/user/use-cases/authenticate-user.js b/packages/core/user/use-cases/authenticate-user.js index a42b8fbde..cc359de86 100644 --- a/packages/core/user/use-cases/authenticate-user.js +++ b/packages/core/user/use-cases/authenticate-user.js @@ -2,12 +2,12 @@ const Boom = require('@hapi/boom'); /** * Use case for authenticating a user using multiple authentication strategies. - * + * * Supports three authentication modes in priority order: * 1. Shared Secret (backend-to-backend with x-frigg-api-key + x-frigg headers) * 2. Adopter JWT (custom JWT authentication) * 3. Frigg Native Token (bearer token from /user/login) - * + * * x-frigg-appUserId and x-frigg-appOrgId headers are automatically supported * for user identification with any auth mode. When present with JWT or Frigg * tokens, they are validated to match the authenticated user. @@ -50,29 +50,18 @@ class AuthenticateUser { const authModes = this.userConfig.authModes || { friggToken: true }; const appUserId = req.headers['x-frigg-appuserid']; const appOrgId = req.headers['x-frigg-apporgid']; - let user = null; - - // DEBUG: Log ALL request headers to catch misspellings - const allHeaders = Object.entries(req.headers).reduce((acc, [key, value]) => { - if (key === 'x-frigg-api-key' || key === 'authorization') { - acc[key] = `${String(value).substring(0, 6)}...(redacted)`; - } else { - acc[key] = value; - } - return acc; - }, {}); - console.log(`[Frigg][DEBUG] ${req.method} ${req.path} - ALL headers:`, JSON.stringify(allHeaders)); - console.log(`[Frigg][DEBUG] Parsed auth values:`, JSON.stringify({ - appUserId: appUserId ?? '(undefined)', - appOrgId: appOrgId ?? '(undefined)', - enabledAuthModes: authModes, - })); + console.log( + '[Frigg] header list:', + JSON.stringify(Object.keys(req.headers)) + ); // Priority 1: Shared Secret (backend-to-backend with API key) if (authModes.sharedSecret !== false) { const apiKey = req.headers['x-frigg-api-key']; if (apiKey) { - console.log(`[Frigg][DEBUG] Taking shared secret auth path`); + console.log( + '[Frigg] Attempting shared secret authentication with API key' + ); // Validate the API key (authentication) await this.authenticateWithSharedSecret.execute(apiKey); // Get user from x-frigg headers (authorization) @@ -81,6 +70,9 @@ class AuthenticateUser { appOrgId ); } + console.log( + '[Frigg] No x-frigg-api-key header found, skipping shared secret authentication' + ); } // Priority 2: Adopter JWT (if enabled) @@ -88,10 +80,11 @@ class AuthenticateUser { authModes.adopterJwt === true && req.headers.authorization?.startsWith('Bearer ') ) { + console.log('[Frigg] Attempting Adopter JWT authentication'); const token = req.headers.authorization.split(' ')[1]; // Detect JWT format (3 parts separated by dots) if (token && token.split('.').length === 3) { - user = await this.getUserFromAdopterJwt.execute(token); + const user = await this.getUserFromAdopterJwt.execute(token); // Validate x-frigg headers match JWT claims if present if (appUserId || appOrgId) { this.validateUserMatch(user, appUserId, appOrgId); @@ -102,7 +95,8 @@ class AuthenticateUser { // Priority 3: Frigg native token (default) if (authModes.friggToken !== false && req.headers.authorization) { - user = await this.getUserFromBearerToken.execute( + console.log('[Frigg] Attempting Frigg native token authentication'); + const user = await this.getUserFromBearerToken.execute( req.headers.authorization ); // Validate x-frigg headers match token user if present @@ -140,5 +134,3 @@ class AuthenticateUser { } module.exports = { AuthenticateUser }; - - diff --git a/packages/core/user/use-cases/get-user-from-x-frigg-headers.js b/packages/core/user/use-cases/get-user-from-x-frigg-headers.js index 399865691..840028571 100644 --- a/packages/core/user/use-cases/get-user-from-x-frigg-headers.js +++ b/packages/core/user/use-cases/get-user-from-x-frigg-headers.js @@ -28,15 +28,6 @@ class GetUserFromXFriggHeaders { * @throws {Boom} 400 Bad Request if neither ID is provided or if both IDs are provided but belong to different users. */ async execute(appUserId, appOrgId) { - console.log(`[Frigg][DEBUG] getUserFromXFriggHeaders called with:`, JSON.stringify({ - appUserId: appUserId || '(falsy)', - appOrgId: appOrgId || '(falsy)', - appUserIdType: typeof appUserId, - appOrgIdType: typeof appOrgId, - individualUserRequired: this.userConfig.individualUserRequired, - organizationUserRequired: this.userConfig.organizationUserRequired, - })); - // At least one header must be provided if (!appUserId && !appOrgId) { throw Boom.badRequest( From d07ab5322a5e9110834139ff9efd53b2350cf266 Mon Sep 17 00:00:00 2001 From: d-klotz Date: Fri, 13 Feb 2026 15:29:53 -0300 Subject: [PATCH 5/5] feat(logging): add detailed logging for OAuth process and errors --- packages/core/handlers/app-handler-helpers.js | 7 +++++++ packages/core/modules/module.js | 1 + .../process-authorization-callback.js | 18 +++++++++++++++++- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/packages/core/handlers/app-handler-helpers.js b/packages/core/handlers/app-handler-helpers.js index cde6bc7d1..66a2b75cf 100644 --- a/packages/core/handlers/app-handler-helpers.js +++ b/packages/core/handlers/app-handler-helpers.js @@ -19,6 +19,11 @@ const createApp = (applyMiddleware) => { }) ); + app.use((req, res, next) => { + console.log(`[Frigg] ${req.method} ${req.path}`); + next(); + }); + if (applyMiddleware) applyMiddleware(app); // Handle sending error response and logging server errors to console @@ -29,6 +34,8 @@ const createApp = (applyMiddleware) => { } = boomError; if (statusCode >= 500) { + console.error(`[Frigg] ${req.method} ${req.path} -> ${statusCode}: ${err.message}`); + console.error(err.stack); flushDebugLog(boomError); res.status(statusCode).json({ error: 'Internal Server Error' }); } else { diff --git a/packages/core/modules/module.js b/packages/core/modules/module.js index 8bf95a03c..3d4a04235 100644 --- a/packages/core/modules/module.js +++ b/packages/core/modules/module.js @@ -92,6 +92,7 @@ class Module extends Delegate { try { if (await this.testAuthRequest(this.api)) validAuth = true; } catch (e) { + console.error(`[Frigg][testAuth] Failed for module ${this.name}: ${e.message}`); flushDebugLog(e); } return validAuth; diff --git a/packages/core/modules/use-cases/process-authorization-callback.js b/packages/core/modules/use-cases/process-authorization-callback.js index 77bc682c4..61feadcd0 100644 --- a/packages/core/modules/use-cases/process-authorization-callback.js +++ b/packages/core/modules/use-cases/process-authorization-callback.js @@ -15,6 +15,8 @@ class ProcessAuthorizationCallback { } async execute(userId, entityType, params) { + console.log(`[Frigg][OAuth] Starting callback for entityType=${entityType}, userId=${userId}`); + const moduleDefinition = this.moduleDefinitions.find((def) => { return entityType === def.moduleName; }); @@ -34,26 +36,37 @@ class ProcessAuthorizationCallback { definition: moduleDefinition, }); + const authType = module.apiClass.requesterType; + console.log(`[Frigg][OAuth] Module created: name=${module.getName()}, authType=${authType}`); + let tokenResponse; - if (module.apiClass.requesterType === ModuleConstants.authType.oauth2) { + if (authType === ModuleConstants.authType.oauth2) { + console.log(`[Frigg][OAuth] Exchanging authorization code for token...`); tokenResponse = await moduleDefinition.requiredAuthMethods.getToken( module.api, params ); + console.log(`[Frigg][OAuth] Token exchange successful, keys: ${Object.keys(tokenResponse || {}).join(', ')}`); } else { + console.log(`[Frigg][OAuth] Setting auth params (non-OAuth2)...`); tokenResponse = await moduleDefinition.requiredAuthMethods.setAuthParams( module.api, params ); await this.onTokenUpdate(module, moduleDefinition, userId); + console.log(`[Frigg][OAuth] Auth params set and credential persisted`); } + console.log(`[Frigg][OAuth] Testing auth...`); const authRes = await module.testAuth(); if (!authRes) { + console.error(`[Frigg][OAuth] testAuth() returned false — authorization failed`); throw new Error('Authorization failed'); } + console.log(`[Frigg][OAuth] Auth test passed`); + console.log(`[Frigg][OAuth] Fetching entity details...`); const entityDetails = await moduleDefinition.requiredAuthMethods.getEntityDetails( module.api, @@ -61,17 +74,20 @@ class ProcessAuthorizationCallback { tokenResponse, userId ); + console.log(`[Frigg][OAuth] Entity details received: identifiers=${JSON.stringify(entityDetails.identifiers)}`); Object.assign( entityDetails.details, module.apiParamsFromEntity(module.api) ); + console.log(`[Frigg][OAuth] Finding or creating entity...`); const persistedEntity = await this.findOrCreateEntity( entityDetails, entityType, module.credential.id ); + console.log(`[Frigg][OAuth] Done — entity_id=${persistedEntity.id}, credential_id=${module.credential.id}`); return { credential_id: module.credential.id,