@friggframework/core 2.0.0-next.114 → 2.0.0-next.116

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -419,7 +419,7 @@ class IntegrationRepositoryMongo extends IntegrationRepositoryInterface {
419
419
  for (const [key, value] of Object.entries(patch)) {
420
420
  $set[`config.${key}`] = value;
421
421
  }
422
- $set.updatedAt = new Date();
422
+ $set.updatedAt = { $date: new Date().toISOString() };
423
423
 
424
424
  const result = await this.prisma.$runCommandRaw({
425
425
  findAndModify: 'Integration',
@@ -120,7 +120,7 @@ class ProcessRepositoryMongo extends ProcessRepositoryInterface {
120
120
  if (normalized.newState !== null) {
121
121
  $set.state = normalized.newState;
122
122
  }
123
- $set.updatedAt = new Date();
123
+ $set.updatedAt = { $date: new Date().toISOString() };
124
124
  update.$set = $set;
125
125
 
126
126
  if (Object.keys(normalized.pushSlice).length > 0) {
@@ -1,5 +1,8 @@
1
1
  const { Module } = require('../module');
2
2
  const { ModuleConstants } = require('../ModuleConstants');
3
+ const { getLogger } = require('../../logs');
4
+
5
+ const log = getLogger('frigg.modules.authorization_callback');
3
6
 
4
7
  // Statuses considered "broken" for an integration whose credentials have just
5
8
  // been successfully re-authorized. Both ERROR (system-driven auth failure) and
@@ -28,10 +31,12 @@ class ProcessAuthorizationCallback {
28
31
  }
29
32
 
30
33
  async execute(userId, entityType, params) {
31
- const hasCode = Boolean(params && params.code);
32
- console.log(
33
- `[Frigg] processAuthorizationCallback start userId=${userId} entityType=${entityType} hasCode=${hasCode}`
34
- );
34
+ log.debug('Authorization callback started', {
35
+ eventName: `${log.name}.started`,
36
+ userId,
37
+ entityType,
38
+ hasCode: Boolean(params && params.code),
39
+ });
35
40
 
36
41
  const moduleDefinition = this.moduleDefinitions.find((def) => {
37
42
  return entityType === def.moduleName;
@@ -58,9 +63,11 @@ class ProcessAuthorizationCallback {
58
63
  : null;
59
64
 
60
65
  if (existingEntity) {
61
- console.log(
62
- `[Frigg] processAuthorizationCallback found existing entity id=${existingEntity.id} credentialId=${existingEntity.credential?.id}`
63
- );
66
+ log.debug('Existing entity found', {
67
+ eventName: `${log.name}.existing_entity_found`,
68
+ entityId: existingEntity.id,
69
+ credentialId: existingEntity.credential?.id,
70
+ });
64
71
  }
65
72
 
66
73
  const module = new Module({
@@ -69,15 +76,26 @@ class ProcessAuthorizationCallback {
69
76
  definition: moduleDefinition,
70
77
  });
71
78
 
79
+ const authType = module.apiClass.requesterType;
80
+ log.debug('Module created', {
81
+ eventName: `${log.name}.module_created`,
82
+ moduleName: module.getName(),
83
+ authType,
84
+ });
85
+
72
86
  let tokenResponse;
73
- if (module.apiClass.requesterType === ModuleConstants.authType.oauth2) {
87
+ if (authType === ModuleConstants.authType.oauth2) {
88
+ log.debug('Exchanging authorization code for token', {
89
+ eventName: `${log.name}.token_exchanging`,
90
+ });
74
91
  tokenResponse = await moduleDefinition.requiredAuthMethods.getToken(
75
92
  module.api,
76
93
  params
77
94
  );
78
- console.log(
79
- `[Frigg] processAuthorizationCallback OAuth getToken complete userId=${userId} entityType=${entityType}`
80
- );
95
+ log.debug('Token exchange completed', {
96
+ eventName: `${log.name}.token_exchanged`,
97
+ tokenKeys: Object.keys(tokenResponse || {}),
98
+ });
81
99
  // Belt-and-suspenders: persist tokens explicitly here rather than
82
100
  // relying solely on the DLGT_TOKEN_UPDATE notification chain
83
101
  // inside setTokens. The notification path remains in place but
@@ -86,6 +104,9 @@ class ProcessAuthorizationCallback {
86
104
  // OAuth flow appears to succeed.
87
105
  await this.onTokenUpdate(module, moduleDefinition, userId);
88
106
  } else {
107
+ log.debug('Setting auth params', {
108
+ eventName: `${log.name}.auth_params_setting`,
109
+ });
89
110
  tokenResponse =
90
111
  await moduleDefinition.requiredAuthMethods.setAuthParams(
91
112
  module.api,
@@ -94,15 +115,24 @@ class ProcessAuthorizationCallback {
94
115
  await this.onTokenUpdate(module, moduleDefinition, userId);
95
116
  }
96
117
 
97
- console.log(
98
- `[Frigg] processAuthorizationCallback credential persisted credentialId=${module.credential?.id} authIsValid=${module.credential?.authIsValid}`
99
- );
118
+ log.debug('Credential persisted', {
119
+ eventName: `${log.name}.credential_persisted`,
120
+ credentialId: module.credential?.id,
121
+ authIsValid: module.credential?.authIsValid,
122
+ });
100
123
 
124
+ log.debug('Testing auth', { eventName: `${log.name}.auth_testing` });
101
125
  const authRes = await module.testAuth();
102
126
  if (!authRes) {
103
127
  throw new Error('Authorization failed');
104
128
  }
129
+ log.debug('Auth test passed', {
130
+ eventName: `${log.name}.auth_test_passed`,
131
+ });
105
132
 
133
+ log.debug('Fetching entity details', {
134
+ eventName: `${log.name}.entity_details_fetching`,
135
+ });
106
136
  const entityDetails =
107
137
  await moduleDefinition.requiredAuthMethods.getEntityDetails(
108
138
  module.api,
@@ -110,17 +140,29 @@ class ProcessAuthorizationCallback {
110
140
  tokenResponse,
111
141
  userId
112
142
  );
143
+ log.debug('Entity details received', {
144
+ eventName: `${log.name}.entity_details_received`,
145
+ externalId: entityDetails.identifiers?.externalId,
146
+ });
113
147
 
114
148
  Object.assign(
115
149
  entityDetails.details,
116
150
  module.apiParamsFromEntity(module.api)
117
151
  );
118
152
 
153
+ log.debug('Finding or creating entity', {
154
+ eventName: `${log.name}.entity_resolving`,
155
+ });
119
156
  const persistedEntity = await this.findOrCreateEntity(
120
157
  entityDetails,
121
158
  entityType,
122
159
  module.credential.id
123
160
  );
161
+ log.debug('Authorization callback completed', {
162
+ eventName: `${log.name}.completed`,
163
+ entityId: persistedEntity.id,
164
+ credentialId: module.credential.id,
165
+ });
124
166
 
125
167
  // Best-effort: a hiccup here must not fail a successful re-auth whose
126
168
  // credential + entity are already persisted. Operators can recover
@@ -129,14 +171,17 @@ class ProcessAuthorizationCallback {
129
171
  const restoredCount = await this.restoreIntegrationsForEntity(
130
172
  persistedEntity.id
131
173
  );
132
- console.log(
133
- `[Frigg] processAuthorizationCallback restored ${restoredCount} integration(s) for entityId=${persistedEntity.id}`
134
- );
174
+ log.debug('Integrations restored', {
175
+ eventName: `${log.name}.integrations_restored`,
176
+ entityId: persistedEntity.id,
177
+ restoredCount,
178
+ });
135
179
  } catch (err) {
136
- console.error(
137
- `[Frigg] Failed to restore integrations for entity ${persistedEntity.id} after successful re-auth — manual intervention may be needed`,
138
- err
139
- );
180
+ log.error('Failed to restore integrations after re-auth', {
181
+ eventName: `${log.name}.integrations_restore_failed`,
182
+ entityId: persistedEntity.id,
183
+ error: err,
184
+ });
140
185
  }
141
186
 
142
187
  return {
@@ -155,9 +200,12 @@ class ProcessAuthorizationCallback {
155
200
  let restored = 0;
156
201
  for (const integration of integrations) {
157
202
  if (STATUSES_RESET_ON_REAUTH.includes(integration.status)) {
158
- console.log(
159
- `[Frigg] Restoring integration ${integration.id} from ${integration.status} to ENABLED after successful re-auth (entityId=${entityId})`
160
- );
203
+ log.info('Integration restored to ENABLED after re-auth', {
204
+ eventName: `${log.name}.integration_restored`,
205
+ integrationId: integration.id,
206
+ previousStatus: integration.status,
207
+ entityId,
208
+ });
161
209
  await this.integrationRepository.updateIntegrationStatus(
162
210
  integration.id,
163
211
  'ENABLED'
@@ -219,9 +267,12 @@ class ProcessAuthorizationCallback {
219
267
  credentialId &&
220
268
  String(existingCredentialId) !== String(credentialId)
221
269
  ) {
222
- console.log(
223
- `[Frigg] Repointing entity ${existingEntity.id} credentialId ${existingCredentialId} -> ${credentialId} after re-auth`
224
- );
270
+ log.info('Entity credential repointed after re-auth', {
271
+ eventName: `${log.name}.entity_credential_repointed`,
272
+ entityId: existingEntity.id,
273
+ previousCredentialId: existingCredentialId,
274
+ credentialId,
275
+ });
225
276
  const updated = await this.moduleRepository.updateEntity(
226
277
  existingEntity.id,
227
278
  { credential: credentialId }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@friggframework/core",
3
3
  "prettier": "@friggframework/prettier-config",
4
- "version": "2.0.0-next.114",
4
+ "version": "2.0.0-next.116",
5
5
  "dependencies": {
6
6
  "@aws-sdk/client-apigatewaymanagementapi": "^3.588.0",
7
7
  "@aws-sdk/client-kms": "^3.588.0",
@@ -47,9 +47,9 @@
47
47
  }
48
48
  },
49
49
  "devDependencies": {
50
- "@friggframework/eslint-config": "2.0.0-next.114",
51
- "@friggframework/prettier-config": "2.0.0-next.114",
52
- "@friggframework/test": "2.0.0-next.114",
50
+ "@friggframework/eslint-config": "2.0.0-next.116",
51
+ "@friggframework/prettier-config": "2.0.0-next.116",
52
+ "@friggframework/test": "2.0.0-next.116",
53
53
  "@prisma/client": "^6.19.3",
54
54
  "@types/lodash": "4.17.15",
55
55
  "@typescript-eslint/eslint-plugin": "^8.0.0",
@@ -89,5 +89,5 @@
89
89
  "publishConfig": {
90
90
  "access": "public"
91
91
  },
92
- "gitHead": "5e56fb857cb3cc0ccf9e033690ecb37cf3e6730c"
92
+ "gitHead": "c9a9e785544241098e614d89c980aeba9574606f"
93
93
  }
@@ -1,13 +1,16 @@
1
1
  const Boom = require('@hapi/boom');
2
+ const { getLogger } = require('../../logs');
3
+
4
+ const log = getLogger('frigg.user.authentication');
2
5
 
3
6
  /**
4
7
  * Use case for authenticating a user using multiple authentication strategies.
5
- *
8
+ *
6
9
  * Supports three authentication modes in priority order:
7
10
  * 1. Shared Secret (backend-to-backend with x-frigg-api-key + x-frigg headers)
8
11
  * 2. Adopter JWT (custom JWT authentication)
9
12
  * 3. Frigg Native Token (bearer token from /user/login)
10
- *
13
+ *
11
14
  * x-frigg-appUserId and x-frigg-appOrgId headers are automatically supported
12
15
  * for user identification with any auth mode. When present with JWT or Frigg
13
16
  * tokens, they are validated to match the authenticated user.
@@ -50,12 +53,18 @@ class AuthenticateUser {
50
53
  const authModes = this.userConfig.authModes || { friggToken: true };
51
54
  const appUserId = req.headers['x-frigg-appuserid'];
52
55
  const appOrgId = req.headers['x-frigg-apporgid'];
53
- let user = null;
56
+ log.debug('Request headers received', {
57
+ eventName: `${log.name}.headers_received`,
58
+ headerNames: Object.keys(req.headers),
59
+ });
54
60
 
55
61
  // Priority 1: Shared Secret (backend-to-backend with API key)
56
62
  if (authModes.sharedSecret !== false) {
57
63
  const apiKey = req.headers['x-frigg-api-key'];
58
64
  if (apiKey) {
65
+ log.debug('Attempting shared secret authentication', {
66
+ eventName: `${log.name}.shared_secret_attempted`,
67
+ });
59
68
  // Validate the API key (authentication)
60
69
  await this.authenticateWithSharedSecret.execute(apiKey);
61
70
  // Get user from x-frigg headers (authorization)
@@ -64,6 +73,9 @@ class AuthenticateUser {
64
73
  appOrgId
65
74
  );
66
75
  }
76
+ log.debug('No x-frigg-api-key header, skipping shared secret', {
77
+ eventName: `${log.name}.shared_secret_skipped`,
78
+ });
67
79
  }
68
80
 
69
81
  // Priority 2: Adopter JWT (if enabled)
@@ -71,10 +83,13 @@ class AuthenticateUser {
71
83
  authModes.adopterJwt === true &&
72
84
  req.headers.authorization?.startsWith('Bearer ')
73
85
  ) {
86
+ log.debug('Attempting adopter JWT authentication', {
87
+ eventName: `${log.name}.adopter_jwt_attempted`,
88
+ });
74
89
  const token = req.headers.authorization.split(' ')[1];
75
90
  // Detect JWT format (3 parts separated by dots)
76
91
  if (token && token.split('.').length === 3) {
77
- user = await this.getUserFromAdopterJwt.execute(token);
92
+ const user = await this.getUserFromAdopterJwt.execute(token);
78
93
  // Validate x-frigg headers match JWT claims if present
79
94
  if (appUserId || appOrgId) {
80
95
  this.validateUserMatch(user, appUserId, appOrgId);
@@ -85,7 +100,10 @@ class AuthenticateUser {
85
100
 
86
101
  // Priority 3: Frigg native token (default)
87
102
  if (authModes.friggToken !== false && req.headers.authorization) {
88
- user = await this.getUserFromBearerToken.execute(
103
+ log.debug('Attempting Frigg native token authentication', {
104
+ eventName: `${log.name}.frigg_token_attempted`,
105
+ });
106
+ const user = await this.getUserFromBearerToken.execute(
89
107
  req.headers.authorization
90
108
  );
91
109
  // Validate x-frigg headers match token user if present
@@ -123,5 +141,3 @@ class AuthenticateUser {
123
141
  }
124
142
 
125
143
  module.exports = { AuthenticateUser };
126
-
127
-