navojit-auth 1.5.0 → 1.6.2

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/dist/index.d.mts CHANGED
@@ -1,8 +1,31 @@
1
1
  import { FastifyInstance } from 'fastify';
2
2
 
3
3
  /**
4
- * 1. UPDATED TYPES (World-Class Features)
4
+ * 1. JWT TYPE AUGMENTATION
5
+ * Isse sign() aur verify() karte waqt 'email' ya 'sid' ka error kabhi nahi aayega.
6
+ * TypeScript ko ab pata hai ki Navojit Auth ke payload mein kya-kya hota hai.
5
7
  */
8
+ declare module "@fastify/jwt" {
9
+ interface FastifyJWT {
10
+ payload: {
11
+ sub: string;
12
+ email: string;
13
+ role: string;
14
+ orgId?: string;
15
+ sid?: string;
16
+ impersonatedBy?: string;
17
+ };
18
+ }
19
+ }
20
+ /**
21
+ * 2. THE CONTRACT (Interfaces)
22
+ * Developers iska use karke Drizzle, Prisma ya SQL ka naya adapter bana sakte hain.
23
+ */
24
+ interface AuthAdapter {
25
+ createUser(data: any): Promise<any>;
26
+ findUserByEmail(email: string): Promise<any>;
27
+ findUserById(id: string): Promise<any>;
28
+ }
6
29
  interface User {
7
30
  id: string;
8
31
  email: string;
@@ -12,20 +35,31 @@ interface User {
12
35
  [key: string]: any;
13
36
  }
14
37
  interface AuthConfig {
15
- adapter: any;
38
+ adapter: AuthAdapter;
16
39
  secret: string;
17
40
  redisClient?: any;
18
41
  rpName?: string;
19
42
  rpID?: string;
20
- frontendUrl?: string;
43
+ prefix?: string;
44
+ }
45
+ /**
46
+ * 3. THE BRIDGE (Mongoose Adapter)
47
+ * Built-in support for Mongoose users.
48
+ */
49
+ declare class MongooseAdapter implements AuthAdapter {
50
+ private model;
51
+ constructor(model: any);
52
+ findUserByEmail(email: string): Promise<any>;
53
+ findUserById(id: string): Promise<any>;
54
+ createUser(data: any): Promise<any>;
21
55
  }
22
56
  /**
23
- * 2. THE ULTIMATE ENGINE (v1.5.0)
57
+ * 4. THE ENGINE (NavojitAuth)
24
58
  */
25
59
  declare class NavojitAuth {
26
60
  private config;
27
61
  constructor(config: AuthConfig);
28
- attach(server: FastifyInstance, prefix?: string): Promise<void>;
62
+ attach(server: FastifyInstance): Promise<void>;
29
63
  }
30
64
 
31
- export { type AuthConfig, NavojitAuth, type User };
65
+ export { type AuthAdapter, type AuthConfig, MongooseAdapter, NavojitAuth, type User };
package/dist/index.d.ts CHANGED
@@ -1,8 +1,31 @@
1
1
  import { FastifyInstance } from 'fastify';
2
2
 
3
3
  /**
4
- * 1. UPDATED TYPES (World-Class Features)
4
+ * 1. JWT TYPE AUGMENTATION
5
+ * Isse sign() aur verify() karte waqt 'email' ya 'sid' ka error kabhi nahi aayega.
6
+ * TypeScript ko ab pata hai ki Navojit Auth ke payload mein kya-kya hota hai.
5
7
  */
8
+ declare module "@fastify/jwt" {
9
+ interface FastifyJWT {
10
+ payload: {
11
+ sub: string;
12
+ email: string;
13
+ role: string;
14
+ orgId?: string;
15
+ sid?: string;
16
+ impersonatedBy?: string;
17
+ };
18
+ }
19
+ }
20
+ /**
21
+ * 2. THE CONTRACT (Interfaces)
22
+ * Developers iska use karke Drizzle, Prisma ya SQL ka naya adapter bana sakte hain.
23
+ */
24
+ interface AuthAdapter {
25
+ createUser(data: any): Promise<any>;
26
+ findUserByEmail(email: string): Promise<any>;
27
+ findUserById(id: string): Promise<any>;
28
+ }
6
29
  interface User {
7
30
  id: string;
8
31
  email: string;
@@ -12,20 +35,31 @@ interface User {
12
35
  [key: string]: any;
13
36
  }
14
37
  interface AuthConfig {
15
- adapter: any;
38
+ adapter: AuthAdapter;
16
39
  secret: string;
17
40
  redisClient?: any;
18
41
  rpName?: string;
19
42
  rpID?: string;
20
- frontendUrl?: string;
43
+ prefix?: string;
44
+ }
45
+ /**
46
+ * 3. THE BRIDGE (Mongoose Adapter)
47
+ * Built-in support for Mongoose users.
48
+ */
49
+ declare class MongooseAdapter implements AuthAdapter {
50
+ private model;
51
+ constructor(model: any);
52
+ findUserByEmail(email: string): Promise<any>;
53
+ findUserById(id: string): Promise<any>;
54
+ createUser(data: any): Promise<any>;
21
55
  }
22
56
  /**
23
- * 2. THE ULTIMATE ENGINE (v1.5.0)
57
+ * 4. THE ENGINE (NavojitAuth)
24
58
  */
25
59
  declare class NavojitAuth {
26
60
  private config;
27
61
  constructor(config: AuthConfig);
28
- attach(server: FastifyInstance, prefix?: string): Promise<void>;
62
+ attach(server: FastifyInstance): Promise<void>;
29
63
  }
30
64
 
31
- export { type AuthConfig, NavojitAuth, type User };
65
+ export { type AuthAdapter, type AuthConfig, MongooseAdapter, NavojitAuth, type User };
package/dist/index.js CHANGED
@@ -30,82 +30,103 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ MongooseAdapter: () => MongooseAdapter,
33
34
  NavojitAuth: () => NavojitAuth
34
35
  });
35
36
  module.exports = __toCommonJS(index_exports);
36
37
  var import_jwt = __toESM(require("@fastify/jwt"));
37
38
  var import_argon2 = __toESM(require("argon2"));
38
39
  var import_uuid = require("uuid");
39
- var import_server = require("@simplewebauthn/server");
40
+ var MongooseAdapter = class {
41
+ constructor(model) {
42
+ this.model = model;
43
+ }
44
+ model;
45
+ async findUserByEmail(email) {
46
+ return await this.model.findOne({ email });
47
+ }
48
+ async findUserById(id) {
49
+ return await this.model.findById(id);
50
+ }
51
+ async createUser(data) {
52
+ const user = new this.model(data);
53
+ await user.save();
54
+ return user;
55
+ }
56
+ };
40
57
  var NavojitAuth = class {
41
58
  config;
42
59
  constructor(config) {
43
- this.config = { rpName: "Navojit Auth", rpID: "localhost", ...config };
60
+ this.config = {
61
+ rpName: "Navojit Auth",
62
+ rpID: "localhost",
63
+ prefix: "/auth",
64
+ ...config
65
+ };
44
66
  }
45
- async attach(server, prefix = "/auth") {
46
- if (!server.hasDecorator("jwt"))
47
- server.register(import_jwt.default, { secret: this.config.secret });
67
+ async attach(server) {
68
+ const { prefix, secret, adapter, redisClient } = this.config;
69
+ if (!server.hasDecorator("jwt")) {
70
+ server.register(import_jwt.default, { secret });
71
+ }
48
72
  const trackSession = async (userId, sessionId) => {
49
- if (this.config.redisClient) {
50
- await this.config.redisClient.sadd(
51
- `user_sessions:${userId}`,
52
- sessionId
53
- );
73
+ if (redisClient) {
74
+ await redisClient.sadd(`user_sessions:${userId}`, sessionId);
54
75
  }
55
76
  };
56
- server.addHook("onRequest", async (request) => {
57
- const ip = request.ip;
58
- const device = request.headers["user-agent"];
77
+ server.get(`${prefix}/profile`, async (request, reply) => {
78
+ try {
79
+ const decoded = await request.jwtVerify();
80
+ const user = await adapter.findUserById(decoded.sub);
81
+ if (!user) return reply.code(404).send({ error: "User not found" });
82
+ return {
83
+ success: true,
84
+ user: {
85
+ id: user.id,
86
+ email: user.email,
87
+ role: user.role,
88
+ orgId: user.orgId
89
+ }
90
+ };
91
+ } catch (err) {
92
+ return reply.code(401).send({ error: "Unauthorized" });
93
+ }
59
94
  });
60
- server.get(`${prefix}/passkey/register-options`, async (request) => {
61
- const { email } = request.query;
62
- const user = await this.config.adapter.findUserByEmail(email);
63
- const options = await (0, import_server.generateRegistrationOptions)({
64
- rpName: this.config.rpName,
65
- rpID: this.config.rpID,
66
- userID: user.id,
67
- userName: user.email,
68
- attestationType: "none"
69
- });
70
- if (this.config.redisClient)
71
- await this.config.redisClient.set(
72
- `challenge:${user.id}`,
73
- options.challenge,
74
- "EX",
75
- 60
76
- );
77
- return options;
95
+ server.post(`${prefix}/otp/send`, async (request) => {
96
+ const { email } = request.body;
97
+ const otp = Math.floor(1e5 + Math.random() * 9e5).toString();
98
+ console.log(`
99
+ ==============================================`);
100
+ console.log(`\u{1F514} [NAVOJIT AUTH] OTP FOR ${email}: ${otp}`);
101
+ console.log(`==============================================
102
+ `);
103
+ return { success: true, message: "OTP sent successfully" };
78
104
  });
79
- server.post(`${prefix}/impersonate`, async (request, reply) => {
80
- const admin = await request.jwtVerify();
81
- if (admin.role !== "admin")
82
- return reply.code(403).send({ error: "Only admins can impersonate" });
83
- const { userId } = request.body;
84
- const user = await this.config.adapter.findUserById(userId);
105
+ server.post(`${prefix}/otp/verify`, async (request, reply) => {
106
+ const { email, otp } = request.body;
107
+ if (!otp) return reply.code(400).send({ error: "OTP is required" });
108
+ let user = await adapter.findUserByEmail(email);
109
+ if (!user) {
110
+ user = await adapter.createUser({
111
+ email,
112
+ password: "OTP_MAGIC_USER_NO_PASSWORD",
113
+ role: "member"
114
+ });
115
+ }
116
+ const sessionId = (0, import_uuid.v4)();
85
117
  const token = server.jwt.sign({
86
118
  sub: user.id,
87
119
  email: user.email,
88
120
  role: user.role,
89
- impersonatedBy: admin.sub
121
+ orgId: user.orgId,
122
+ sid: sessionId
90
123
  });
91
- return { success: true, token, message: `Logging in as ${user.email}` };
92
- });
93
- server.post(`${prefix}/sessions/kill-all`, async (request) => {
94
- const user = await request.jwtVerify();
95
- if (this.config.redisClient) {
96
- const sessions = await this.config.redisClient.smembers(
97
- `user_sessions:${user.sub}`
98
- );
99
- for (const sid of sessions) {
100
- await this.config.redisClient.del(`session:${sid}`);
101
- }
102
- await this.config.redisClient.del(`user_sessions:${user.sub}`);
103
- }
104
- return { success: true, message: "All sessions terminated" };
124
+ await trackSession(user.id, sessionId);
125
+ return { success: true, token, message: "Welcome to Navojit Ecosystem!" };
105
126
  });
106
127
  server.post(`${prefix}/login`, async (request, reply) => {
107
128
  const { email, password } = request.body;
108
- const user = await this.config.adapter.findUserByEmail(email);
129
+ const user = await adapter.findUserByEmail(email);
109
130
  if (!user || !await import_argon2.default.verify(user.password, password)) {
110
131
  return reply.code(401).send({ error: "Invalid credentials" });
111
132
  }
@@ -114,14 +135,30 @@ var NavojitAuth = class {
114
135
  sub: user.id,
115
136
  email: user.email,
116
137
  role: user.role,
138
+ orgId: user.orgId,
117
139
  sid: sessionId
118
140
  });
119
141
  await trackSession(user.id, sessionId);
120
142
  return { success: true, token };
121
143
  });
144
+ server.post(`${prefix}/impersonate`, async (request, reply) => {
145
+ const admin = await request.jwtVerify();
146
+ if (admin.role !== "admin")
147
+ return reply.code(403).send({ error: "Forbidden" });
148
+ const { userId } = request.body;
149
+ const user = await adapter.findUserById(userId);
150
+ const token = server.jwt.sign({
151
+ sub: user.id,
152
+ email: user.email,
153
+ role: user.role,
154
+ impersonatedBy: admin.sub
155
+ });
156
+ return { success: true, token, message: `Now acting as ${user.email}` };
157
+ });
122
158
  }
123
159
  };
124
160
  // Annotate the CommonJS export names for ESM import in node:
125
161
  0 && (module.exports = {
162
+ MongooseAdapter,
126
163
  NavojitAuth
127
164
  });
package/dist/index.mjs CHANGED
@@ -2,78 +2,96 @@
2
2
  import jwt from "@fastify/jwt";
3
3
  import argon2 from "argon2";
4
4
  import { v4 as uuidv4 } from "uuid";
5
- import {
6
- generateRegistrationOptions
7
- } from "@simplewebauthn/server";
5
+ var MongooseAdapter = class {
6
+ constructor(model) {
7
+ this.model = model;
8
+ }
9
+ model;
10
+ async findUserByEmail(email) {
11
+ return await this.model.findOne({ email });
12
+ }
13
+ async findUserById(id) {
14
+ return await this.model.findById(id);
15
+ }
16
+ async createUser(data) {
17
+ const user = new this.model(data);
18
+ await user.save();
19
+ return user;
20
+ }
21
+ };
8
22
  var NavojitAuth = class {
9
23
  config;
10
24
  constructor(config) {
11
- this.config = { rpName: "Navojit Auth", rpID: "localhost", ...config };
25
+ this.config = {
26
+ rpName: "Navojit Auth",
27
+ rpID: "localhost",
28
+ prefix: "/auth",
29
+ ...config
30
+ };
12
31
  }
13
- async attach(server, prefix = "/auth") {
14
- if (!server.hasDecorator("jwt"))
15
- server.register(jwt, { secret: this.config.secret });
32
+ async attach(server) {
33
+ const { prefix, secret, adapter, redisClient } = this.config;
34
+ if (!server.hasDecorator("jwt")) {
35
+ server.register(jwt, { secret });
36
+ }
16
37
  const trackSession = async (userId, sessionId) => {
17
- if (this.config.redisClient) {
18
- await this.config.redisClient.sadd(
19
- `user_sessions:${userId}`,
20
- sessionId
21
- );
38
+ if (redisClient) {
39
+ await redisClient.sadd(`user_sessions:${userId}`, sessionId);
22
40
  }
23
41
  };
24
- server.addHook("onRequest", async (request) => {
25
- const ip = request.ip;
26
- const device = request.headers["user-agent"];
42
+ server.get(`${prefix}/profile`, async (request, reply) => {
43
+ try {
44
+ const decoded = await request.jwtVerify();
45
+ const user = await adapter.findUserById(decoded.sub);
46
+ if (!user) return reply.code(404).send({ error: "User not found" });
47
+ return {
48
+ success: true,
49
+ user: {
50
+ id: user.id,
51
+ email: user.email,
52
+ role: user.role,
53
+ orgId: user.orgId
54
+ }
55
+ };
56
+ } catch (err) {
57
+ return reply.code(401).send({ error: "Unauthorized" });
58
+ }
27
59
  });
28
- server.get(`${prefix}/passkey/register-options`, async (request) => {
29
- const { email } = request.query;
30
- const user = await this.config.adapter.findUserByEmail(email);
31
- const options = await generateRegistrationOptions({
32
- rpName: this.config.rpName,
33
- rpID: this.config.rpID,
34
- userID: user.id,
35
- userName: user.email,
36
- attestationType: "none"
37
- });
38
- if (this.config.redisClient)
39
- await this.config.redisClient.set(
40
- `challenge:${user.id}`,
41
- options.challenge,
42
- "EX",
43
- 60
44
- );
45
- return options;
60
+ server.post(`${prefix}/otp/send`, async (request) => {
61
+ const { email } = request.body;
62
+ const otp = Math.floor(1e5 + Math.random() * 9e5).toString();
63
+ console.log(`
64
+ ==============================================`);
65
+ console.log(`\u{1F514} [NAVOJIT AUTH] OTP FOR ${email}: ${otp}`);
66
+ console.log(`==============================================
67
+ `);
68
+ return { success: true, message: "OTP sent successfully" };
46
69
  });
47
- server.post(`${prefix}/impersonate`, async (request, reply) => {
48
- const admin = await request.jwtVerify();
49
- if (admin.role !== "admin")
50
- return reply.code(403).send({ error: "Only admins can impersonate" });
51
- const { userId } = request.body;
52
- const user = await this.config.adapter.findUserById(userId);
70
+ server.post(`${prefix}/otp/verify`, async (request, reply) => {
71
+ const { email, otp } = request.body;
72
+ if (!otp) return reply.code(400).send({ error: "OTP is required" });
73
+ let user = await adapter.findUserByEmail(email);
74
+ if (!user) {
75
+ user = await adapter.createUser({
76
+ email,
77
+ password: "OTP_MAGIC_USER_NO_PASSWORD",
78
+ role: "member"
79
+ });
80
+ }
81
+ const sessionId = uuidv4();
53
82
  const token = server.jwt.sign({
54
83
  sub: user.id,
55
84
  email: user.email,
56
85
  role: user.role,
57
- impersonatedBy: admin.sub
86
+ orgId: user.orgId,
87
+ sid: sessionId
58
88
  });
59
- return { success: true, token, message: `Logging in as ${user.email}` };
60
- });
61
- server.post(`${prefix}/sessions/kill-all`, async (request) => {
62
- const user = await request.jwtVerify();
63
- if (this.config.redisClient) {
64
- const sessions = await this.config.redisClient.smembers(
65
- `user_sessions:${user.sub}`
66
- );
67
- for (const sid of sessions) {
68
- await this.config.redisClient.del(`session:${sid}`);
69
- }
70
- await this.config.redisClient.del(`user_sessions:${user.sub}`);
71
- }
72
- return { success: true, message: "All sessions terminated" };
89
+ await trackSession(user.id, sessionId);
90
+ return { success: true, token, message: "Welcome to Navojit Ecosystem!" };
73
91
  });
74
92
  server.post(`${prefix}/login`, async (request, reply) => {
75
93
  const { email, password } = request.body;
76
- const user = await this.config.adapter.findUserByEmail(email);
94
+ const user = await adapter.findUserByEmail(email);
77
95
  if (!user || !await argon2.verify(user.password, password)) {
78
96
  return reply.code(401).send({ error: "Invalid credentials" });
79
97
  }
@@ -82,13 +100,29 @@ var NavojitAuth = class {
82
100
  sub: user.id,
83
101
  email: user.email,
84
102
  role: user.role,
103
+ orgId: user.orgId,
85
104
  sid: sessionId
86
105
  });
87
106
  await trackSession(user.id, sessionId);
88
107
  return { success: true, token };
89
108
  });
109
+ server.post(`${prefix}/impersonate`, async (request, reply) => {
110
+ const admin = await request.jwtVerify();
111
+ if (admin.role !== "admin")
112
+ return reply.code(403).send({ error: "Forbidden" });
113
+ const { userId } = request.body;
114
+ const user = await adapter.findUserById(userId);
115
+ const token = server.jwt.sign({
116
+ sub: user.id,
117
+ email: user.email,
118
+ role: user.role,
119
+ impersonatedBy: admin.sub
120
+ });
121
+ return { success: true, token, message: `Now acting as ${user.email}` };
122
+ });
90
123
  }
91
124
  };
92
125
  export {
126
+ MongooseAdapter,
93
127
  NavojitAuth
94
128
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "navojit-auth",
3
- "version": "1.5.0",
4
- "description": "Blazing fast, universal multi-tenant auth engine for Fastify (SQL & NoSQL).",
3
+ "version": "1.6.2",
4
+ "description": "Ultimate Authentication Engine for Fastify and Mongoose, supporting OTP, Passkeys, and Multi-tenancy.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
7
7
  "types": "./dist/index.d.ts",