Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion packages/core/handlers/app-handler-helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Redact all x-frigg API keys before logging headers

This redaction logic only masks x-frigg-api-key, but it logs every other x-frigg* header value verbatim, which can leak credentials into logs on any handled 4xx path. The codebase already uses other secret headers (x-frigg-health-api-key in packages/core/handlers/routers/health.js and x-frigg-admin-api-key in packages/core/handlers/routers/db-migration.js), so those keys will now be exposed if present when an error reaches this handler.

Useful? React with 👍 / 👎.

return acc;
}, {});
console.warn(`[Frigg] ${req.method} ${req.path} -> ${statusCode}: ${err.message}`, JSON.stringify({ authHeaders }));
res.status(statusCode).json({ error: err.message });
}
});
Expand Down
18 changes: 18 additions & 0 deletions packages/core/user/use-cases/authenticate-user.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
9 changes: 9 additions & 0 deletions packages/core/user/use-cases/get-user-from-x-frigg-headers.js
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Loading