strapi-plugin-firebase-authentication 1.1.0 → 1.1.7

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.
@@ -410,7 +410,7 @@ const firebaseController = {
410
410
  const result = await strapi.plugin(pluginName).service("firebaseService").validateFirebaseToken(idToken, profileMetaData, populate2);
411
411
  ctx.body = result;
412
412
  } catch (error2) {
413
- strapi.log.error("validateToken controller error:", error2);
413
+ strapi.log.error("validateToken controller error:", error2.message);
414
414
  if (error2.name === "ValidationError") {
415
415
  return ctx.badRequest(error2.message);
416
416
  }
@@ -500,9 +500,11 @@ const firebaseController = {
500
500
  }
501
501
  },
502
502
  /**
503
- * Reset password - authenticated with 1hr JWT
503
+ * Reset password - authenticated password change
504
504
  * POST /api/firebase-authentication/resetPassword
505
- * Public endpoint - uses JWT from Authorization header
505
+ * Public endpoint - requires valid JWT in Authorization header
506
+ * Used for admin-initiated resets or user self-service password changes
507
+ * NOT used for forgot password email flow (which uses Firebase's hosted UI)
506
508
  */
507
509
  async resetPassword(ctx) {
508
510
  strapi.log.debug("resetPassword endpoint called");
@@ -5186,13 +5188,13 @@ lodash.exports;
5186
5188
  return string2.slice(position, position + target.length) == target;
5187
5189
  }
5188
5190
  function template(string2, options2, guard) {
5189
- var settings2 = lodash2.templateSettings;
5191
+ var settings = lodash2.templateSettings;
5190
5192
  if (guard && isIterateeCall(string2, options2, guard)) {
5191
5193
  options2 = undefined$1;
5192
5194
  }
5193
5195
  string2 = toString4(string2);
5194
- options2 = assignInWith({}, options2, settings2, customDefaultsAssignIn);
5195
- var imports = assignInWith({}, options2.imports, settings2.imports, customDefaultsAssignIn), importsKeys = keys2(imports), importsValues = baseValues(imports, importsKeys);
5196
+ options2 = assignInWith({}, options2, settings, customDefaultsAssignIn);
5197
+ var imports = assignInWith({}, options2.imports, settings.imports, customDefaultsAssignIn), importsKeys = keys2(imports), importsValues = baseValues(imports, importsKeys);
5196
5198
  var isEscaping, isEvaluating, index2 = 0, interpolate = options2.interpolate || reNoMatch, source = "__p += '";
5197
5199
  var reDelimiters = RegExp2(
5198
5200
  (options2.escape || reNoMatch).source + "|" + interpolate.source + "|" + (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + "|" + (options2.evaluate || reNoMatch).source + "|$",
@@ -28902,9 +28904,6 @@ const userController = {
28902
28904
  }
28903
28905
  };
28904
28906
  const settingsController = {
28905
- setToken: async (ctx) => {
28906
- ctx.body = await strapi.plugin("firebase-authentication").service("settingsService").setToken(ctx);
28907
- },
28908
28907
  setFirebaseConfigJson: async (ctx) => {
28909
28908
  ctx.body = await strapi.plugin("firebase-authentication").service("settingsService").setFirebaseConfigJson(ctx);
28910
28909
  },
@@ -29059,13 +29058,7 @@ const controllers = {
29059
29058
  };
29060
29059
  const middlewares = {};
29061
29060
  const policies = {};
29062
- const settings = [
29063
- {
29064
- method: "POST",
29065
- path: "/settings/token",
29066
- handler: "settingsController.setToken",
29067
- config: { policies: ["admin::isAuthenticatedAdmin"] }
29068
- },
29061
+ const settingsRoute = [
29069
29062
  {
29070
29063
  method: "POST",
29071
29064
  path: "/settings/firebase-config",
@@ -29099,75 +29092,9 @@ const settings = [
29099
29092
  ];
29100
29093
  const admin = {
29101
29094
  type: "admin",
29102
- routes: [...settings]
29103
- };
29104
- const contentApi = {
29105
- type: "content-api",
29106
- routes: [
29107
- {
29108
- method: "POST",
29109
- path: "/",
29110
- handler: "firebaseController.validateToken",
29111
- config: {
29112
- auth: false,
29113
- // Public endpoint - this IS the authentication endpoint
29114
- policies: []
29115
- }
29116
- },
29117
- {
29118
- method: "POST",
29119
- path: "/emailLogin",
29120
- handler: "firebaseController.emailLogin",
29121
- config: {
29122
- auth: false,
29123
- // Public endpoint - email/password login
29124
- policies: []
29125
- }
29126
- },
29127
- {
29128
- method: "POST",
29129
- path: "/forgotPassword",
29130
- handler: "firebaseController.forgotPassword",
29131
- config: {
29132
- auth: false,
29133
- // Public endpoint - no authentication required
29134
- policies: []
29135
- }
29136
- },
29137
- {
29138
- method: "POST",
29139
- path: "/resetPassword",
29140
- handler: "firebaseController.resetPassword",
29141
- config: {
29142
- auth: false,
29143
- // Public endpoint - uses JWT from Authorization header
29144
- policies: []
29145
- }
29146
- },
29147
- {
29148
- method: "GET",
29149
- path: "/config",
29150
- handler: "settingsController.getPublicConfig",
29151
- config: {
29152
- auth: false,
29153
- // Public endpoint - frontend needs this for validation
29154
- policies: []
29155
- }
29156
- },
29157
- {
29158
- method: "POST",
29159
- path: "/requestMagicLink",
29160
- handler: "firebaseController.requestMagicLink",
29161
- config: {
29162
- auth: false,
29163
- // Public endpoint - passwordless authentication
29164
- policies: []
29165
- }
29166
- }
29167
- ]
29168
- };
29169
- const contentInternalApi = {
29170
29095
  routes: [
29096
+ ...settingsRoute,
29097
+ // User management routes
29171
29098
  {
29172
29099
  method: "GET",
29173
29100
  path: "/users",
@@ -29231,23 +29158,77 @@ const contentInternalApi = {
29231
29158
  config: {
29232
29159
  policies: ["admin::isAuthenticatedAdmin"]
29233
29160
  }
29161
+ }
29162
+ ]
29163
+ };
29164
+ const contentApi = {
29165
+ type: "content-api",
29166
+ routes: [
29167
+ {
29168
+ method: "POST",
29169
+ path: "/",
29170
+ handler: "firebaseController.validateToken",
29171
+ config: {
29172
+ auth: false,
29173
+ // Public endpoint - this IS the authentication endpoint
29174
+ policies: []
29175
+ }
29176
+ },
29177
+ {
29178
+ method: "POST",
29179
+ path: "/emailLogin",
29180
+ handler: "firebaseController.emailLogin",
29181
+ config: {
29182
+ auth: false,
29183
+ // Public endpoint - email/password login
29184
+ policies: []
29185
+ }
29186
+ },
29187
+ {
29188
+ method: "POST",
29189
+ path: "/forgotPassword",
29190
+ handler: "firebaseController.forgotPassword",
29191
+ config: {
29192
+ auth: false,
29193
+ // Public endpoint - no authentication required
29194
+ policies: []
29195
+ }
29196
+ },
29197
+ {
29198
+ method: "POST",
29199
+ path: "/resetPassword",
29200
+ handler: "firebaseController.resetPassword",
29201
+ config: {
29202
+ auth: false,
29203
+ // Public endpoint - authenticated password change, requires valid JWT in Authorization header
29204
+ policies: []
29205
+ }
29234
29206
  },
29235
29207
  {
29236
29208
  method: "GET",
29237
29209
  path: "/config",
29238
29210
  handler: "settingsController.getPublicConfig",
29239
29211
  config: {
29212
+ auth: false,
29213
+ // Public endpoint - frontend needs this for validation
29240
29214
  policies: []
29241
- // This is intentionally public for frontend config
29242
29215
  }
29243
29216
  },
29244
- ...settings
29217
+ {
29218
+ method: "POST",
29219
+ path: "/requestMagicLink",
29220
+ handler: "firebaseController.requestMagicLink",
29221
+ config: {
29222
+ auth: false,
29223
+ // Public endpoint - passwordless authentication
29224
+ policies: []
29225
+ }
29226
+ }
29245
29227
  ]
29246
29228
  };
29247
29229
  const routes = {
29248
29230
  admin,
29249
- "content-api": contentApi,
29250
- "content-internal-api": contentInternalApi
29231
+ "content-api": contentApi
29251
29232
  };
29252
29233
  const checkValidJson = (jsonString) => {
29253
29234
  try {
@@ -29539,7 +29520,7 @@ const settingsService = ({ strapi: strapi2 }) => {
29539
29520
  /**
29540
29521
  * Updates only the magic link settings without affecting other configuration
29541
29522
  */
29542
- async updateMagicLinkSettings(settings2) {
29523
+ async updateMagicLinkSettings(settings) {
29543
29524
  try {
29544
29525
  const foundConfig = await strapi2.db.query(CONFIG_CONTENT_TYPE).findOne({ where: {} });
29545
29526
  if (!foundConfig) {
@@ -29548,10 +29529,10 @@ const settingsService = ({ strapi: strapi2 }) => {
29548
29529
  const result = await strapi2.db.query(CONFIG_CONTENT_TYPE).update({
29549
29530
  where: { id: foundConfig.id },
29550
29531
  data: {
29551
- enableMagicLink: settings2.enableMagicLink,
29552
- magicLinkUrl: settings2.magicLinkUrl,
29553
- magicLinkEmailSubject: settings2.magicLinkEmailSubject,
29554
- magicLinkExpiryHours: settings2.magicLinkExpiryHours
29532
+ enableMagicLink: settings.enableMagicLink,
29533
+ magicLinkUrl: settings.magicLinkUrl,
29534
+ magicLinkEmailSubject: settings.magicLinkEmailSubject,
29535
+ magicLinkExpiryHours: settings.magicLinkExpiryHours
29555
29536
  }
29556
29537
  });
29557
29538
  return {
@@ -29967,7 +29948,7 @@ const userService = ({ strapi: strapi2 }) => {
29967
29948
  try {
29968
29949
  const actionCodeSettings = {
29969
29950
  url: passwordResetUrl,
29970
- handleCodeInApp: true
29951
+ handleCodeInApp: false
29971
29952
  };
29972
29953
  const timeoutPromise = new Promise((_2, reject) => {
29973
29954
  setTimeout(
@@ -30188,17 +30169,13 @@ const firebaseService = ({ strapi: strapi2 }) => ({
30188
30169
  });
30189
30170
  if (userByEmail) {
30190
30171
  validateUserNotBlocked(userByEmail);
30191
- try {
30192
- await strapi2.plugin("firebase-authentication").service("firebaseUserDataService").updateForUser(userByEmail.documentId, {
30193
- firebaseUserID: firebaseUID
30194
- });
30195
- strapi2.log.info(`Auto-linked user ${userByEmail.username} to Firebase UID ${firebaseUID}`);
30196
- } catch (error2) {
30197
- if (error2.code !== "23505") {
30198
- throw error2;
30199
- }
30200
- strapi2.log.info(`User ${userByEmail.username} already linked to Firebase (race condition handled)`);
30172
+ const existingLink = await strapi2.plugin("firebase-authentication").service("firebaseUserDataService").getByFirebaseUID(firebaseUID);
30173
+ if (existingLink && existingLink.user) {
30174
+ validateUserNotBlocked(existingLink.user);
30175
+ return existingLink.user;
30201
30176
  }
30177
+ await strapi2.plugin("firebase-authentication").service("firebaseUserDataService").updateForUser(userByEmail.documentId, { firebaseUserID: firebaseUID });
30178
+ strapi2.log.info(`Auto-linked user ${userByEmail.username} to Firebase UID ${firebaseUID}`);
30202
30179
  return userByEmail;
30203
30180
  }
30204
30181
  const firebaseDataByApple = await strapi2.documents("plugin::firebase-authentication.firebase-user-data").findMany({
@@ -30212,21 +30189,13 @@ const firebaseService = ({ strapi: strapi2 }) => ({
30212
30189
  const userByAppleEmail = firebaseDataByApple?.[0]?.user || null;
30213
30190
  if (userByAppleEmail) {
30214
30191
  validateUserNotBlocked(userByAppleEmail);
30215
- try {
30216
- await strapi2.plugin("firebase-authentication").service("firebaseUserDataService").updateForUser(userByAppleEmail.documentId, {
30217
- firebaseUserID: firebaseUID
30218
- });
30219
- strapi2.log.info(
30220
- `Auto-linked Apple user ${userByAppleEmail.username} to Firebase UID ${firebaseUID}`
30221
- );
30222
- } catch (error2) {
30223
- if (error2.code !== "23505") {
30224
- throw error2;
30225
- }
30226
- strapi2.log.info(
30227
- `User ${userByAppleEmail.username} already linked to Firebase (race condition handled)`
30228
- );
30192
+ const existingLink = await strapi2.plugin("firebase-authentication").service("firebaseUserDataService").getByFirebaseUID(firebaseUID);
30193
+ if (existingLink && existingLink.user) {
30194
+ validateUserNotBlocked(existingLink.user);
30195
+ return existingLink.user;
30229
30196
  }
30197
+ await strapi2.plugin("firebase-authentication").service("firebaseUserDataService").updateForUser(userByAppleEmail.documentId, { firebaseUserID: firebaseUID });
30198
+ strapi2.log.info(`Auto-linked Apple user ${userByAppleEmail.username} to Firebase UID ${firebaseUID}`);
30230
30199
  return userByAppleEmail;
30231
30200
  }
30232
30201
  }
@@ -30237,17 +30206,13 @@ const firebaseService = ({ strapi: strapi2 }) => ({
30237
30206
  });
30238
30207
  if (userByPhone) {
30239
30208
  validateUserNotBlocked(userByPhone);
30240
- try {
30241
- await strapi2.plugin("firebase-authentication").service("firebaseUserDataService").updateForUser(userByPhone.documentId, {
30242
- firebaseUserID: firebaseUID
30243
- });
30244
- strapi2.log.info(`Auto-linked phone user ${userByPhone.username} to Firebase UID ${firebaseUID}`);
30245
- } catch (error2) {
30246
- if (error2.code !== "23505") {
30247
- throw error2;
30248
- }
30249
- strapi2.log.info(`User ${userByPhone.username} already linked to Firebase (race condition handled)`);
30209
+ const existingLink = await strapi2.plugin("firebase-authentication").service("firebaseUserDataService").getByFirebaseUID(firebaseUID);
30210
+ if (existingLink && existingLink.user) {
30211
+ validateUserNotBlocked(existingLink.user);
30212
+ return existingLink.user;
30250
30213
  }
30214
+ await strapi2.plugin("firebase-authentication").service("firebaseUserDataService").updateForUser(userByPhone.documentId, { firebaseUserID: firebaseUID });
30215
+ strapi2.log.info(`Auto-linked phone user ${userByPhone.username} to Firebase UID ${firebaseUID}`);
30251
30216
  return userByPhone;
30252
30217
  }
30253
30218
  }
@@ -30274,12 +30239,13 @@ const firebaseService = ({ strapi: strapi2 }) => ({
30274
30239
  type: "plugin",
30275
30240
  name: "users-permissions"
30276
30241
  });
30277
- const settings2 = await pluginStore.get({
30242
+ const settings = await pluginStore.get({
30278
30243
  key: "advanced"
30279
30244
  });
30280
- const role = await strapi2.db.query("plugin::users-permissions.role").findOne({ where: { type: settings2.default_role } });
30245
+ const role = await strapi2.db.query("plugin::users-permissions.role").findOne({ where: { type: settings.default_role } });
30281
30246
  userPayload.role = role.id;
30282
30247
  userPayload.confirmed = true;
30248
+ userPayload.provider = "firebase";
30283
30249
  userPayload.email = decodedToken.email;
30284
30250
  userPayload.phoneNumber = decodedToken.phone_number;
30285
30251
  if (profileMetaData) {
@@ -30315,7 +30281,22 @@ const firebaseService = ({ strapi: strapi2 }) => ({
30315
30281
  strapi2.log.info(`Created user ${newUser.username} and linked to Firebase UID ${decodedToken.uid}`);
30316
30282
  return newUser;
30317
30283
  } catch (error2) {
30318
- if (newUser) {
30284
+ if (error2.code === "23505") {
30285
+ strapi2.log.warn(
30286
+ `[Race Condition] User creation conflict for Firebase UID ${decodedToken.uid}. Another concurrent request created the user first. Retrying lookup...`
30287
+ );
30288
+ const existingUser = await strapi2.plugin("firebase-authentication").service("firebaseService").checkIfUserExists(decodedToken);
30289
+ if (existingUser) {
30290
+ strapi2.log.info(
30291
+ `[Race Condition] Successfully found user ${existingUser.username} created by concurrent request`
30292
+ );
30293
+ return existingUser;
30294
+ }
30295
+ strapi2.log.error(
30296
+ `[Race Condition] Failed to find user after race condition retry for Firebase UID ${decodedToken.uid}`
30297
+ );
30298
+ }
30299
+ if (error2.code !== "23505" && newUser) {
30319
30300
  try {
30320
30301
  await strapi2.db.query("plugin::users-permissions.user").delete({
30321
30302
  where: { documentId: newUser.documentId }
@@ -30451,7 +30432,7 @@ const firebaseService = ({ strapi: strapi2 }) => ({
30451
30432
  },
30452
30433
  /**
30453
30434
  * Forgot password flow - sends reset email
30454
- * Public endpoint that generates a JWT token and sends a password reset email
30435
+ * Public endpoint that sends a Firebase-hosted password reset email using Firebase's secure hosted UI
30455
30436
  */
30456
30437
  forgotPassword: async (ctx) => {
30457
30438
  const { email: email2 } = ctx.request.body;
@@ -30497,13 +30478,30 @@ const firebaseService = ({ strapi: strapi2 }) => ({
30497
30478
  if (!strapiUser) {
30498
30479
  return { message: "If an account with that email exists, a password reset link has been sent." };
30499
30480
  }
30500
- const jwtService = strapi2.plugin("users-permissions").service("jwt");
30501
- const token = jwtService.issue(
30502
- { id: strapiUser.id },
30503
- // Use numeric id, not documentId
30504
- { expiresIn: "1h" }
30505
- );
30506
- const resetLink = `${resetUrl}?token=${token}`;
30481
+ const actionCodeSettings = {
30482
+ url: resetUrl,
30483
+ // Continue URL after reset completes on Firebase's page
30484
+ handleCodeInApp: false
30485
+ };
30486
+ const timeoutPromise = new Promise((_2, reject) => {
30487
+ setTimeout(
30488
+ () => reject(new Error("Firebase generatePasswordResetLink timeout after 10 seconds")),
30489
+ 1e4
30490
+ );
30491
+ });
30492
+ let resetLink;
30493
+ try {
30494
+ resetLink = await Promise.race([
30495
+ strapi2.firebase.auth().generatePasswordResetLink(strapiUser.email, actionCodeSettings),
30496
+ timeoutPromise
30497
+ ]);
30498
+ strapi2.log.info(
30499
+ `✅ Password reset link generated successfully for ${strapiUser.email}: ${resetLink}`
30500
+ );
30501
+ } catch (error2) {
30502
+ strapi2.log.error(`❌ Failed to generate password reset link for ${strapiUser.email}:`, error2);
30503
+ throw error2;
30504
+ }
30507
30505
  await strapi2.plugin("firebase-authentication").service("emailService").sendPasswordResetEmail(strapiUser, resetLink);
30508
30506
  return {
30509
30507
  message: "If an account with that email exists, a password reset link has been sent."
@@ -30517,7 +30515,17 @@ const firebaseService = ({ strapi: strapi2 }) => ({
30517
30515
  },
30518
30516
  /**
30519
30517
  * Reset password with authenticated JWT
30520
- * Public endpoint that validates a JWT token and resets the user's password
30518
+ * Allows authenticated users (or admins) to change a user's Firebase password
30519
+ *
30520
+ * @param ctx - Koa context with JWT in Authorization header and new password in body
30521
+ * @returns User object and fresh JWT for auto-login
30522
+ *
30523
+ * @remarks
30524
+ * Use cases:
30525
+ * 1. Admin-initiated password reset (via admin panel)
30526
+ * 2. User-initiated password change (when already authenticated)
30527
+ *
30528
+ * NOT used for forgot password email flow - that now uses Firebase's hosted UI
30521
30529
  */
30522
30530
  resetPassword: async (ctx) => {
30523
30531
  const { password } = ctx.request.body;
@@ -31252,7 +31260,7 @@ const firebaseUserDataService = ({ strapi: strapi2 }) => ({
31252
31260
  if (!userId || typeof userId !== "string") {
31253
31261
  throw new Error("Invalid user documentId");
31254
31262
  }
31255
- let firebaseData = await strapi2.documents("plugin::firebase-authentication.firebase-user-data").findOne({
31263
+ let firebaseData = await strapi2.documents("plugin::firebase-authentication.firebase-user-data").findFirst({
31256
31264
  filters: { user: { documentId: { $eq: userId } } },
31257
31265
  populate: ["user"]
31258
31266
  });
@@ -31267,7 +31275,7 @@ const firebaseUserDataService = ({ strapi: strapi2 }) => ({
31267
31275
  * @returns Firebase user data with populated user
31268
31276
  */
31269
31277
  async getByFirebaseUID(firebaseUID) {
31270
- return await strapi2.documents("plugin::firebase-authentication.firebase-user-data").findOne({
31278
+ return await strapi2.documents("plugin::firebase-authentication.firebase-user-data").findFirst({
31271
31279
  filters: { firebaseUserID: { $eq: firebaseUID } },
31272
31280
  populate: ["user"]
31273
31281
  });
@@ -31278,7 +31286,7 @@ const firebaseUserDataService = ({ strapi: strapi2 }) => ({
31278
31286
  * @param data - Fields to update
31279
31287
  */
31280
31288
  async updateForUser(userId, data) {
31281
- let firebaseData = await strapi2.documents("plugin::firebase-authentication.firebase-user-data").findOne({
31289
+ let firebaseData = await strapi2.documents("plugin::firebase-authentication.firebase-user-data").findFirst({
31282
31290
  filters: { user: { documentId: { $eq: userId } } }
31283
31291
  });
31284
31292
  if (!firebaseData) {
@@ -31294,8 +31302,8 @@ const firebaseUserDataService = ({ strapi: strapi2 }) => ({
31294
31302
  });
31295
31303
  } catch (error2) {
31296
31304
  if (error2.code === "23505") {
31297
- strapi2.log.warn(`Race condition detected for user ${userId}, retrying findOne`);
31298
- firebaseData = await strapi2.documents("plugin::firebase-authentication.firebase-user-data").findOne({
31305
+ strapi2.log.warn(`Race condition detected for user ${userId}, retrying findFirst`);
31306
+ firebaseData = await strapi2.documents("plugin::firebase-authentication.firebase-user-data").findFirst({
31299
31307
  filters: { user: { documentId: { $eq: userId } } }
31300
31308
  });
31301
31309
  if (firebaseData) {
@@ -27,9 +27,11 @@ declare const firebaseController: {
27
27
  */
28
28
  forgotPassword(ctx: any): Promise<void>;
29
29
  /**
30
- * Reset password - authenticated with 1hr JWT
30
+ * Reset password - authenticated password change
31
31
  * POST /api/firebase-authentication/resetPassword
32
- * Public endpoint - uses JWT from Authorization header
32
+ * Public endpoint - requires valid JWT in Authorization header
33
+ * Used for admin-initiated resets or user self-service password changes
34
+ * NOT used for forgot password email flow (which uses Firebase's hosted UI)
33
35
  */
34
36
  resetPassword(ctx: any): Promise<void>;
35
37
  requestMagicLink(ctx: Context): Promise<void>;
@@ -20,7 +20,6 @@ declare const _default: {
20
20
  sendResetEmail: (ctx: any) => Promise<void>;
21
21
  };
22
22
  settingsController: {
23
- setToken: (ctx: import("koa").Context | import("koa").DefaultContext) => Promise<void>;
24
23
  setFirebaseConfigJson: (ctx: import("koa").Context | import("koa").DefaultContext) => Promise<void>;
25
24
  getFirebaseConfigJson: (ctx: import("koa").Context | import("koa").DefaultContext) => Promise<any>;
26
25
  delFirebaseConfigJson(ctx: import("koa").Context | import("koa").DefaultContext): Promise<void>;
@@ -1,6 +1,5 @@
1
1
  import { Context, DefaultContext } from "koa";
2
2
  declare const _default: {
3
- setToken: (ctx: DefaultContext | Context) => Promise<void>;
4
3
  setFirebaseConfigJson: (ctx: DefaultContext | Context) => Promise<void>;
5
4
  getFirebaseConfigJson: (ctx: DefaultContext | Context) => Promise<any>;
6
5
  delFirebaseConfigJson(ctx: DefaultContext | Context): Promise<void>;
@@ -41,7 +41,6 @@ declare const _default: {
41
41
  sendResetEmail: (ctx: any) => Promise<void>;
42
42
  };
43
43
  settingsController: {
44
- setToken: (ctx: import("koa").Context | import("koa").DefaultContext) => Promise<void>;
45
44
  setFirebaseConfigJson: (ctx: import("koa").Context | import("koa").DefaultContext) => Promise<void>;
46
45
  getFirebaseConfigJson: (ctx: import("koa").Context | import("koa").DefaultContext) => Promise<any>;
47
46
  delFirebaseConfigJson(ctx: import("koa").Context | import("koa").DefaultContext): Promise<void>;
@@ -57,6 +56,9 @@ declare const _default: {
57
56
  method: string;
58
57
  path: string;
59
58
  handler: string;
59
+ /**
60
+ * Plugin server methods
61
+ */
60
62
  config: {
61
63
  policies: string[];
62
64
  };
@@ -74,16 +76,6 @@ declare const _default: {
74
76
  };
75
77
  }[];
76
78
  };
77
- "content-internal-api": {
78
- routes: {
79
- method: string;
80
- path: string;
81
- handler: string;
82
- config: {
83
- policies: string[];
84
- };
85
- }[];
86
- };
87
79
  };
88
80
  services: {
89
81
  settingsService: ({ strapi }: {
@@ -22,15 +22,5 @@ declare const _default: {
22
22
  };
23
23
  }[];
24
24
  };
25
- "content-internal-api": {
26
- routes: {
27
- method: string;
28
- path: string;
29
- handler: string;
30
- config: {
31
- policies: string[];
32
- };
33
- }[];
34
- };
35
25
  };
36
26
  export default _default;
@@ -66,14 +66,24 @@ declare const _default: ({ strapi }: {
66
66
  }>;
67
67
  /**
68
68
  * Forgot password flow - sends reset email
69
- * Public endpoint that generates a JWT token and sends a password reset email
69
+ * Public endpoint that sends a Firebase-hosted password reset email using Firebase's secure hosted UI
70
70
  */
71
71
  forgotPassword: (ctx: any) => Promise<{
72
72
  message: string;
73
73
  }>;
74
74
  /**
75
75
  * Reset password with authenticated JWT
76
- * Public endpoint that validates a JWT token and resets the user's password
76
+ * Allows authenticated users (or admins) to change a user's Firebase password
77
+ *
78
+ * @param ctx - Koa context with JWT in Authorization header and new password in body
79
+ * @returns User object and fresh JWT for auto-login
80
+ *
81
+ * @remarks
82
+ * Use cases:
83
+ * 1. Admin-initiated password reset (via admin panel)
84
+ * 2. User-initiated password change (when already authenticated)
85
+ *
86
+ * NOT used for forgot password email flow - that now uses Firebase's hosted UI
77
87
  */
78
88
  resetPassword: (ctx: any) => Promise<{
79
89
  user: any;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "strapi-plugin-firebase-authentication",
3
- "version": "1.1.0",
3
+ "version": "1.1.7",
4
4
  "description": "Allows easy integration between clients utilizing Firebase for authentication and Strapi",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -43,6 +43,7 @@
43
43
  "format": "npx prettier --write .",
44
44
  "format:check": "npx prettier -c .",
45
45
  "release": "npm run format && npm run build && npm run verify && changelogen --release && npm publish && git push --follow-tags",
46
+ "changelog": "changelogen --release",
46
47
  "test:ts:back": "run -T tsc -p server/tsconfig.json",
47
48
  "test:ts:front": "run -T tsc -p admin/tsconfig.json",
48
49
  "verify": "strapi-plugin verify",
@@ -50,8 +51,6 @@
50
51
  "watch:link": "strapi-plugin watch:link"
51
52
  },
52
53
  "dependencies": {
53
- "@strapi/design-system": "^2.0.0-rc.16",
54
- "@strapi/icons": "^2.0.0-rc.25",
55
54
  "@tanstack/react-query": "^5.90.2",
56
55
  "crypto-js": "^4.2.0",
57
56
  "destr": "^2.0.5",
@@ -67,8 +66,9 @@
67
66
  },
68
67
  "devDependencies": {
69
68
  "@strapi/sdk-plugin": "^5.3.2",
70
- "@strapi/strapi": "^5.26.0",
71
69
  "@strapi/typescript-utils": "^5.23.3",
70
+ "@strapi/design-system": "^2.0.0-rc.16",
71
+ "@strapi/icons": "^2.0.0-rc.25",
72
72
  "@types/react": "^19.2.2",
73
73
  "@types/react-dom": "^19.2.1",
74
74
  "@types/react-syntax-highlighter": "^15.5.13",
@@ -82,12 +82,13 @@
82
82
  "typescript": "^5.7.3"
83
83
  },
84
84
  "peerDependencies": {
85
- "@strapi/sdk-plugin": "^5.3.2",
86
- "@strapi/strapi": "^5.0.1",
87
- "react": "^19.2.0",
88
- "react-dom": "^19.2.0",
89
- "react-router-dom": "^7.9.3",
90
- "styled-components": "^6.1.19"
85
+ "@strapi/strapi": "^5.0.0",
86
+ "@strapi/design-system": "^2.0.0-rc.0",
87
+ "@strapi/icons": "^2.0.0-rc.0",
88
+ "react": "^18.0.0",
89
+ "react-dom": "^18.0.0",
90
+ "react-router-dom": "^6.0.0",
91
+ "styled-components": "^6.0.0"
91
92
  },
92
93
  "engines": {
93
94
  "node": ">=18.0.0 <=22.x.x",
@@ -1,11 +0,0 @@
1
- declare const _default: {
2
- routes: {
3
- method: string;
4
- path: string;
5
- handler: string;
6
- config: {
7
- policies: string[];
8
- };
9
- }[];
10
- };
11
- export default _default;