@ciscode/authentication-kit 1.1.4 → 1.1.5

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.
package/README.md CHANGED
@@ -74,10 +74,12 @@ POST /api/auth/refresh-token - New access token from a valid refresh token (cook
74
74
  POST /api/auth/request-password-reset - Sends a reset token (e.g., by email).
75
75
  POST /api/auth/reset-password - Consumes the reset token and sets a new password.
76
76
  GET /api/auth/microsoft - GET /api/auth/microsoft/callback - Optional Microsoft Entra OAuth; issues first-party tokens.
77
+ Note: If the Microsoft ID token does not include an email, the response includes `profileIncomplete: true`.
77
78
  Users
78
79
  GET /api/users - List users (paginated).
79
80
  POST /api/users - Create a user.
80
81
  Additional CRUD endpoints as exposed by controllers.
82
+ If `profileIncomplete: true`, update the user profile (e.g., set `email`) via `PUT /api/users/:id`.
81
83
  Roles and Permissions
82
84
  GET/POST /api/auth/roles - Manage roles (name, permissions: string[]).
83
85
  GET /api/auth/permissions - List permission strings and metadata.
@@ -48,10 +48,13 @@ passport_1.default.use(new passport_azure_ad_oauth2_1.Strategy({
48
48
  }, async (_at, _rt, params, _profile, done) => {
49
49
  try {
50
50
  const decoded = (0, jsonwebtoken_1.decode)(params.id_token);
51
- const microsoftId = decoded.oid;
52
- const email = decoded.preferred_username;
51
+ const microsoftId = decoded.oid || decoded.sub;
52
+ const email = decoded.preferred_username || decoded.upn || decoded.email;
53
53
  const name = decoded.name;
54
- let user = await user_model_1.default.findOne({ $or: [{ microsoftId }, { email }] });
54
+ const match = [{ microsoftId }];
55
+ if (email)
56
+ match.push({ email });
57
+ let user = await user_model_1.default.findOne({ $or: match });
55
58
  if (!user) {
56
59
  user = new user_model_1.default({ email, name, microsoftId, roles: [], status: 'active' });
57
60
  await user.save();
@@ -78,10 +81,13 @@ passport_1.default.use('azure_ad_oauth2_client', new passport_azure_ad_oauth2_1.
78
81
  }, async (_at, _rt, params, _profile, done) => {
79
82
  try {
80
83
  const decoded = (0, jsonwebtoken_1.decode)(params.id_token);
81
- const microsoftId = decoded.oid;
82
- const email = decoded.preferred_username;
84
+ const microsoftId = decoded.oid || decoded.sub;
85
+ const email = decoded.preferred_username || decoded.upn || decoded.email;
83
86
  const name = decoded.name;
84
- let client = await client_model_1.default.findOne({ $or: [{ microsoftId }, { email }] });
87
+ const match = [{ microsoftId }];
88
+ if (email)
89
+ match.push({ email });
90
+ let client = await client_model_1.default.findOne({ $or: match });
85
91
  if (!client) {
86
92
  client = new client_model_1.default({ email, name, microsoftId, roles: [] });
87
93
  await client.save();
@@ -77,7 +77,7 @@ let AuthController = class AuthController {
77
77
  path: '/',
78
78
  maxAge: (0, helper_1.getMillisecondsFromExpiry)(refreshTTL),
79
79
  });
80
- return res.status(200).json({ accessToken, refreshToken });
80
+ return res.status(200).json({ accessToken, refreshToken, profileIncomplete: !principal.email });
81
81
  }
82
82
  async respondWebOrMobile(req, res, principal) {
83
83
  const roleDocs = await role_model_1.default.find({ _id: { $in: principal.roles } })
@@ -116,6 +116,7 @@ let AuthController = class AuthController {
116
116
  const url = new URL(mobileRedirect);
117
117
  url.searchParams.set('accessToken', accessToken);
118
118
  url.searchParams.set('refreshToken', refreshToken);
119
+ url.searchParams.set('profileIncomplete', (!principal.email).toString());
119
120
  return res.redirect(302, url.toString());
120
121
  }
121
122
  const isProd = process.env.NODE_ENV === 'production';
@@ -126,7 +127,7 @@ let AuthController = class AuthController {
126
127
  path: '/',
127
128
  maxAge: (0, helper_1.getMillisecondsFromExpiry)(refreshTTL),
128
129
  });
129
- return res.status(200).json({ accessToken, refreshToken });
130
+ return res.status(200).json({ accessToken, refreshToken, profileIncomplete: !principal.email });
130
131
  }
131
132
  async registerClient(req, res) {
132
133
  try {
@@ -228,13 +229,13 @@ let AuthController = class AuthController {
228
229
  console.error('ID token verify failed:', e.message || e);
229
230
  return res.status(401).json({ message: 'Invalid Microsoft ID token.' });
230
231
  }
231
- const email = ms.preferred_username || ms.email;
232
- const name = ms.name;
233
- if (!email) {
234
- return res.status(400).json({ message: 'Email claim missing in Microsoft ID token.' });
235
- }
236
232
  const microsoftId = ms.oid || ms.sub;
237
- let user = await user_model_1.default.findOne({ email });
233
+ const email = ms.preferred_username || ms.upn || ms.email;
234
+ const name = ms.name;
235
+ const match = [{ microsoftId }];
236
+ if (email)
237
+ match.push({ email });
238
+ let user = await user_model_1.default.findOne({ $or: match });
238
239
  if (!user) {
239
240
  user = new user_model_1.default({
240
241
  email,
@@ -367,7 +368,7 @@ let AuthController = class AuthController {
367
368
  path: '/',
368
369
  maxAge: (0, helper_1.getMillisecondsFromExpiry)(refreshTTL),
369
370
  });
370
- return res.status(200).json({ accessToken, refreshToken });
371
+ return res.status(200).json({ accessToken, refreshToken, profileIncomplete: !principal.email });
371
372
  }
372
373
  catch (err) {
373
374
  console.error('googleExchange error:', ((_h = err === null || err === void 0 ? void 0 : err.response) === null || _h === void 0 ? void 0 : _h.data) || err.message || err);
@@ -5,9 +5,9 @@ declare const ClientSchema: mongoose.Schema<any, mongoose.Model<any, any, any, a
5
5
  createdAt: NativeDate;
6
6
  updatedAt: NativeDate;
7
7
  } & {
8
- email: string;
9
8
  roles: mongoose.Types.ObjectId[];
10
9
  createdAt: Date;
10
+ email?: string;
11
11
  name?: string;
12
12
  password?: string;
13
13
  microsoftId?: string;
@@ -20,9 +20,9 @@ declare const ClientSchema: mongoose.Schema<any, mongoose.Model<any, any, any, a
20
20
  createdAt: NativeDate;
21
21
  updatedAt: NativeDate;
22
22
  } & {
23
- email: string;
24
23
  roles: mongoose.Types.ObjectId[];
25
24
  createdAt: Date;
25
+ email?: string;
26
26
  name?: string;
27
27
  password?: string;
28
28
  microsoftId?: string;
@@ -35,9 +35,9 @@ declare const ClientSchema: mongoose.Schema<any, mongoose.Model<any, any, any, a
35
35
  createdAt: NativeDate;
36
36
  updatedAt: NativeDate;
37
37
  } & {
38
- email: string;
39
38
  roles: mongoose.Types.ObjectId[];
40
39
  createdAt: Date;
40
+ email?: string;
41
41
  name?: string;
42
42
  password?: string;
43
43
  microsoftId?: string;
@@ -9,8 +9,11 @@ const mongoose_paginate_v2_1 = __importDefault(require("mongoose-paginate-v2"));
9
9
  const ClientSchema = new mongoose_1.default.Schema({
10
10
  email: {
11
11
  type: String,
12
- required: true,
13
- unique: true
12
+ required: function () {
13
+ return !this.microsoftId && !this.googleId && !this.facebookId;
14
+ },
15
+ unique: true,
16
+ sparse: true
14
17
  },
15
18
  password: {
16
19
  type: String,
@@ -5,10 +5,10 @@ declare const UserSchema: mongoose.Schema<any, mongoose.Model<any, any, any, any
5
5
  createdAt: NativeDate;
6
6
  updatedAt: NativeDate;
7
7
  } & {
8
- email: string;
9
8
  roles: mongoose.Types.ObjectId[];
10
9
  status: "pending" | "active" | "suspended" | "deactivated";
11
10
  failedLoginAttempts: number;
11
+ email?: string;
12
12
  name?: string;
13
13
  password?: string;
14
14
  jobTitle?: string;
@@ -24,10 +24,10 @@ declare const UserSchema: mongoose.Schema<any, mongoose.Model<any, any, any, any
24
24
  createdAt: NativeDate;
25
25
  updatedAt: NativeDate;
26
26
  } & {
27
- email: string;
28
27
  roles: mongoose.Types.ObjectId[];
29
28
  status: "pending" | "active" | "suspended" | "deactivated";
30
29
  failedLoginAttempts: number;
30
+ email?: string;
31
31
  name?: string;
32
32
  password?: string;
33
33
  jobTitle?: string;
@@ -43,10 +43,10 @@ declare const UserSchema: mongoose.Schema<any, mongoose.Model<any, any, any, any
43
43
  createdAt: NativeDate;
44
44
  updatedAt: NativeDate;
45
45
  } & {
46
- email: string;
47
46
  roles: mongoose.Types.ObjectId[];
48
47
  status: "pending" | "active" | "suspended" | "deactivated";
49
48
  failedLoginAttempts: number;
49
+ email?: string;
50
50
  name?: string;
51
51
  password?: string;
52
52
  jobTitle?: string;
@@ -9,8 +9,11 @@ const mongoose_paginate_v2_1 = __importDefault(require("mongoose-paginate-v2"));
9
9
  const UserSchema = new mongoose_1.default.Schema({
10
10
  email: {
11
11
  type: String,
12
- required: true,
13
- unique: true
12
+ required: function () {
13
+ return !this.microsoftId && !this.googleId && !this.facebookId;
14
+ },
15
+ unique: true,
16
+ sparse: true
14
17
  },
15
18
  password: {
16
19
  type: String,
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  "type": "git",
8
8
  "url": "git+https://github.com/CISCODE-MA/AuthKit.git"
9
9
  },
10
- "version": "1.1.4",
10
+ "version": "1.1.5",
11
11
  "description": "A login library with local login, Microsoft Entra ID authentication, password reset, and roles/permissions.",
12
12
  "main": "dist/index.js",
13
13
  "types": "dist/index.d.ts",