navojit-auth 1.6.2 → 4.0.0

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,51 +1,44 @@
1
1
  import { FastifyInstance } from 'fastify';
2
2
 
3
- /**
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.
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
3
  interface AuthAdapter {
25
4
  createUser(data: any): Promise<any>;
26
5
  findUserByEmail(email: string): Promise<any>;
27
6
  findUserById(id: string): Promise<any>;
28
7
  }
29
- interface User {
30
- id: string;
31
- email: string;
32
- role: string;
33
- orgId?: string;
34
- passkeys?: any[];
35
- [key: string]: any;
36
- }
37
8
  interface AuthConfig {
38
9
  adapter: AuthAdapter;
39
10
  secret: string;
40
- redisClient?: any;
41
- rpName?: string;
42
- rpID?: string;
43
11
  prefix?: string;
12
+ accessExpiry?: string;
13
+ refreshExpiry?: string;
14
+ }
15
+ interface OmniTokens {
16
+ access_token: string;
17
+ refresh_token: string;
18
+ sid: string;
19
+ }
20
+ declare class NavojitAuth {
21
+ private config;
22
+ constructor(config: AuthConfig);
23
+ generateOmniTokens(user: any, options?: {
24
+ mfa_v?: boolean;
25
+ am?: string[];
26
+ }): OmniTokens;
27
+ verifyToken(token: string): any;
28
+ generatePasskeyOptions(userId: string, userEmail: string, rpID?: string): Promise<any>;
29
+ verifyPasskey(expectedChallenge: string, responseBody: any, origin: string, rpID?: string): Promise<any>;
30
+ hashPassword(password: string): Promise<string>;
31
+ verifyPassword(hash: string, password: string): Promise<boolean>;
32
+ verifyAndFetchUser(email: string, otp: string): Promise<any>;
33
+ /**
34
+ * 🟢 FASTIFY CONNECTOR
35
+ */
36
+ attach(server: FastifyInstance): Promise<void>;
37
+ /**
38
+ * 🔵 EXPRESS CONNECTOR
39
+ */
40
+ express(): any;
44
41
  }
45
- /**
46
- * 3. THE BRIDGE (Mongoose Adapter)
47
- * Built-in support for Mongoose users.
48
- */
49
42
  declare class MongooseAdapter implements AuthAdapter {
50
43
  private model;
51
44
  constructor(model: any);
@@ -53,13 +46,5 @@ declare class MongooseAdapter implements AuthAdapter {
53
46
  findUserById(id: string): Promise<any>;
54
47
  createUser(data: any): Promise<any>;
55
48
  }
56
- /**
57
- * 4. THE ENGINE (NavojitAuth)
58
- */
59
- declare class NavojitAuth {
60
- private config;
61
- constructor(config: AuthConfig);
62
- attach(server: FastifyInstance): Promise<void>;
63
- }
64
49
 
65
- export { type AuthAdapter, type AuthConfig, MongooseAdapter, NavojitAuth, type User };
50
+ export { type AuthAdapter, type AuthConfig, MongooseAdapter, NavojitAuth, type OmniTokens };
package/dist/index.d.ts CHANGED
@@ -1,51 +1,44 @@
1
1
  import { FastifyInstance } from 'fastify';
2
2
 
3
- /**
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.
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
3
  interface AuthAdapter {
25
4
  createUser(data: any): Promise<any>;
26
5
  findUserByEmail(email: string): Promise<any>;
27
6
  findUserById(id: string): Promise<any>;
28
7
  }
29
- interface User {
30
- id: string;
31
- email: string;
32
- role: string;
33
- orgId?: string;
34
- passkeys?: any[];
35
- [key: string]: any;
36
- }
37
8
  interface AuthConfig {
38
9
  adapter: AuthAdapter;
39
10
  secret: string;
40
- redisClient?: any;
41
- rpName?: string;
42
- rpID?: string;
43
11
  prefix?: string;
12
+ accessExpiry?: string;
13
+ refreshExpiry?: string;
14
+ }
15
+ interface OmniTokens {
16
+ access_token: string;
17
+ refresh_token: string;
18
+ sid: string;
19
+ }
20
+ declare class NavojitAuth {
21
+ private config;
22
+ constructor(config: AuthConfig);
23
+ generateOmniTokens(user: any, options?: {
24
+ mfa_v?: boolean;
25
+ am?: string[];
26
+ }): OmniTokens;
27
+ verifyToken(token: string): any;
28
+ generatePasskeyOptions(userId: string, userEmail: string, rpID?: string): Promise<any>;
29
+ verifyPasskey(expectedChallenge: string, responseBody: any, origin: string, rpID?: string): Promise<any>;
30
+ hashPassword(password: string): Promise<string>;
31
+ verifyPassword(hash: string, password: string): Promise<boolean>;
32
+ verifyAndFetchUser(email: string, otp: string): Promise<any>;
33
+ /**
34
+ * 🟢 FASTIFY CONNECTOR
35
+ */
36
+ attach(server: FastifyInstance): Promise<void>;
37
+ /**
38
+ * 🔵 EXPRESS CONNECTOR
39
+ */
40
+ express(): any;
44
41
  }
45
- /**
46
- * 3. THE BRIDGE (Mongoose Adapter)
47
- * Built-in support for Mongoose users.
48
- */
49
42
  declare class MongooseAdapter implements AuthAdapter {
50
43
  private model;
51
44
  constructor(model: any);
@@ -53,13 +46,5 @@ declare class MongooseAdapter implements AuthAdapter {
53
46
  findUserById(id: string): Promise<any>;
54
47
  createUser(data: any): Promise<any>;
55
48
  }
56
- /**
57
- * 4. THE ENGINE (NavojitAuth)
58
- */
59
- declare class NavojitAuth {
60
- private config;
61
- constructor(config: AuthConfig);
62
- attach(server: FastifyInstance): Promise<void>;
63
- }
64
49
 
65
- export { type AuthAdapter, type AuthConfig, MongooseAdapter, NavojitAuth, type User };
50
+ export { type AuthAdapter, type AuthConfig, MongooseAdapter, NavojitAuth, type OmniTokens };
package/dist/index.js CHANGED
@@ -34,127 +34,190 @@ __export(index_exports, {
34
34
  NavojitAuth: () => NavojitAuth
35
35
  });
36
36
  module.exports = __toCommonJS(index_exports);
37
- var import_jwt = __toESM(require("@fastify/jwt"));
38
- var import_argon2 = __toESM(require("argon2"));
37
+ var import_jsonwebtoken = __toESM(require("jsonwebtoken"));
39
38
  var import_uuid = require("uuid");
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
- };
39
+ var import_server = require("@simplewebauthn/server");
40
+ var argon2 = __toESM(require("argon2"));
57
41
  var NavojitAuth = class {
58
42
  config;
59
43
  constructor(config) {
60
44
  this.config = {
61
- rpName: "Navojit Auth",
62
- rpID: "localhost",
63
45
  prefix: "/auth",
46
+ accessExpiry: "15m",
47
+ refreshExpiry: "30d",
64
48
  ...config
65
49
  };
66
50
  }
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
- }
72
- const trackSession = async (userId, sessionId) => {
73
- if (redisClient) {
74
- await redisClient.sadd(`user_sessions:${userId}`, sessionId);
51
+ // --------------------------------------------------
52
+ // 🚀 CORE 1: UNIVERSAL TOKENS (Syncs with Py/Rust)
53
+ // --------------------------------------------------
54
+ generateOmniTokens(user, options = {}) {
55
+ const sid = (0, import_uuid.v4)();
56
+ const userId = user.id || user._id.toString();
57
+ const access_token = import_jsonwebtoken.default.sign(
58
+ {
59
+ sub: userId,
60
+ email: user.email,
61
+ role: user.role || "member",
62
+ sid,
63
+ mfa_v: options.mfa_v || false,
64
+ am: options.am || ["pwd"],
65
+ typ: "access"
66
+ },
67
+ this.config.secret,
68
+ { expiresIn: this.config.accessExpiry }
69
+ );
70
+ const refresh_token = import_jsonwebtoken.default.sign(
71
+ {
72
+ sub: userId,
73
+ sid,
74
+ typ: "refresh"
75
+ },
76
+ this.config.secret,
77
+ { expiresIn: this.config.refreshExpiry }
78
+ );
79
+ return { access_token, refresh_token, sid };
80
+ }
81
+ verifyToken(token) {
82
+ try {
83
+ return import_jsonwebtoken.default.verify(token, this.config.secret);
84
+ } catch (error) {
85
+ if (error.name === "TokenExpiredError") {
86
+ return { error: "expired", message: "Token has expired" };
75
87
  }
76
- };
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" });
88
+ return { error: "invalid", message: error.message };
89
+ }
90
+ }
91
+ // --------------------------------------------------
92
+ // 👁️ CORE 2: BIOMETRICS & PASSKEYS (World-Class Security)
93
+ // --------------------------------------------------
94
+ async generatePasskeyOptions(userId, userEmail, rpID = "navojit.com") {
95
+ return (0, import_server.generateRegistrationOptions)({
96
+ rpName: "Navojit Ecosystem",
97
+ rpID,
98
+ userID: Buffer.from(userId),
99
+ userName: userEmail,
100
+ attestationType: "none",
101
+ authenticatorSelection: {
102
+ residentKey: "required",
103
+ userVerification: "preferred"
93
104
  }
94
105
  });
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" };
104
- });
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"
106
+ }
107
+ async verifyPasskey(expectedChallenge, responseBody, origin, rpID = "navojit.com") {
108
+ try {
109
+ const verification = await (0, import_server.verifyRegistrationResponse)({
110
+ response: responseBody,
111
+ expectedChallenge,
112
+ expectedOrigin: origin,
113
+ expectedRPID: rpID
114
+ });
115
+ return verification;
116
+ } catch (error) {
117
+ return { verified: false, error: error.message };
118
+ }
119
+ }
120
+ // --------------------------------------------------
121
+ // 🔐 CORE 3: ARGON2 & OTP LOGIC
122
+ // --------------------------------------------------
123
+ async hashPassword(password) {
124
+ return await argon2.hash(password);
125
+ }
126
+ async verifyPassword(hash2, password) {
127
+ return await argon2.verify(hash2, password);
128
+ }
129
+ async verifyAndFetchUser(email, otp) {
130
+ if (!otp || otp.length < 4) throw new Error("Invalid OTP");
131
+ let user = await this.config.adapter.findUserByEmail(email);
132
+ if (!user) {
133
+ user = await this.config.adapter.createUser({
134
+ email,
135
+ password: await this.hashPassword("NAV_SECURE_" + (0, import_uuid.v4)()),
136
+ role: "member",
137
+ isVerified: true
138
+ });
139
+ }
140
+ return user;
141
+ }
142
+ // ==========================================
143
+ // 3. THE CONNECTORS (Purane Features Wapas!)
144
+ // ==========================================
145
+ /**
146
+ * 🟢 FASTIFY CONNECTOR
147
+ */
148
+ async attach(server) {
149
+ const { prefix, adapter } = this.config;
150
+ server.post(`${prefix}/otp/verify`, async (req, reply) => {
151
+ try {
152
+ const user = await this.verifyAndFetchUser(
153
+ req.body.email,
154
+ req.body.otp
155
+ );
156
+ const tokens = this.generateOmniTokens(user, {
157
+ mfa_v: true,
158
+ am: ["otp"]
114
159
  });
160
+ return { success: true, ...tokens, gateway: "navojit-v4-fastify" };
161
+ } catch (e) {
162
+ return reply.code(400).send({ error: e.message });
115
163
  }
116
- const sessionId = (0, import_uuid.v4)();
117
- const token = server.jwt.sign({
118
- sub: user.id,
119
- email: user.email,
120
- role: user.role,
121
- orgId: user.orgId,
122
- sid: sessionId
123
- });
124
- await trackSession(user.id, sessionId);
125
- return { success: true, token, message: "Welcome to Navojit Ecosystem!" };
126
164
  });
127
- server.post(`${prefix}/login`, async (request, reply) => {
128
- const { email, password } = request.body;
129
- const user = await adapter.findUserByEmail(email);
130
- if (!user || !await import_argon2.default.verify(user.password, password)) {
131
- return reply.code(401).send({ error: "Invalid credentials" });
165
+ server.addHook("preHandler", async (req, reply) => {
166
+ if (req.routerPath.startsWith(`${prefix}/profile`)) {
167
+ const token = req.headers.authorization?.split(" ")[1];
168
+ if (!token) return reply.code(401).send({ error: "Missing Token" });
169
+ const decoded = this.verifyToken(token);
170
+ if (decoded.error)
171
+ return reply.code(401).send({ error: decoded.error });
172
+ req.user = decoded;
132
173
  }
133
- const sessionId = (0, import_uuid.v4)();
134
- const token = server.jwt.sign({
135
- sub: user.id,
136
- email: user.email,
137
- role: user.role,
138
- orgId: user.orgId,
139
- sid: sessionId
140
- });
141
- await trackSession(user.id, sessionId);
142
- return { success: true, token };
143
174
  });
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}` };
175
+ server.get(`${prefix}/profile`, async (req, reply) => {
176
+ const user = await adapter.findUserById(req.user.sub);
177
+ return {
178
+ success: true,
179
+ user: { id: user.id, email: user.email, role: user.role }
180
+ };
181
+ });
182
+ }
183
+ /**
184
+ * 🔵 EXPRESS CONNECTOR
185
+ */
186
+ express() {
187
+ const express = require("express");
188
+ const router = express.Router();
189
+ const { prefix, adapter } = this.config;
190
+ router.post(`${prefix}/otp/verify`, async (req, res) => {
191
+ try {
192
+ const user = await this.verifyAndFetchUser(
193
+ req.body.email,
194
+ req.body.otp
195
+ );
196
+ const tokens = this.generateOmniTokens(user, {
197
+ mfa_v: true,
198
+ am: ["otp"]
199
+ });
200
+ res.json({ success: true, ...tokens, gateway: "navojit-v4-express" });
201
+ } catch (e) {
202
+ res.status(400).json({ error: e.message });
203
+ }
157
204
  });
205
+ return router;
206
+ }
207
+ };
208
+ var MongooseAdapter = class {
209
+ constructor(model) {
210
+ this.model = model;
211
+ }
212
+ model;
213
+ async findUserByEmail(email) {
214
+ return await this.model.findOne({ email });
215
+ }
216
+ async findUserById(id) {
217
+ return await this.model.findById(id);
218
+ }
219
+ async createUser(data) {
220
+ return await new this.model(data).save();
158
221
  }
159
222
  };
160
223
  // Annotate the CommonJS export names for ESM import in node:
package/dist/index.mjs CHANGED
@@ -1,125 +1,198 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
1
8
  // src/index.ts
2
- import jwt from "@fastify/jwt";
3
- import argon2 from "argon2";
9
+ import jwt from "jsonwebtoken";
4
10
  import { v4 as uuidv4 } from "uuid";
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
- };
11
+ import {
12
+ generateRegistrationOptions,
13
+ verifyRegistrationResponse
14
+ } from "@simplewebauthn/server";
15
+ import * as argon2 from "argon2";
22
16
  var NavojitAuth = class {
23
17
  config;
24
18
  constructor(config) {
25
19
  this.config = {
26
- rpName: "Navojit Auth",
27
- rpID: "localhost",
28
20
  prefix: "/auth",
21
+ accessExpiry: "15m",
22
+ refreshExpiry: "30d",
29
23
  ...config
30
24
  };
31
25
  }
32
- async attach(server) {
33
- const { prefix, secret, adapter, redisClient } = this.config;
34
- if (!server.hasDecorator("jwt")) {
35
- server.register(jwt, { secret });
36
- }
37
- const trackSession = async (userId, sessionId) => {
38
- if (redisClient) {
39
- await redisClient.sadd(`user_sessions:${userId}`, sessionId);
26
+ // --------------------------------------------------
27
+ // 🚀 CORE 1: UNIVERSAL TOKENS (Syncs with Py/Rust)
28
+ // --------------------------------------------------
29
+ generateOmniTokens(user, options = {}) {
30
+ const sid = uuidv4();
31
+ const userId = user.id || user._id.toString();
32
+ const access_token = jwt.sign(
33
+ {
34
+ sub: userId,
35
+ email: user.email,
36
+ role: user.role || "member",
37
+ sid,
38
+ mfa_v: options.mfa_v || false,
39
+ am: options.am || ["pwd"],
40
+ typ: "access"
41
+ },
42
+ this.config.secret,
43
+ { expiresIn: this.config.accessExpiry }
44
+ );
45
+ const refresh_token = jwt.sign(
46
+ {
47
+ sub: userId,
48
+ sid,
49
+ typ: "refresh"
50
+ },
51
+ this.config.secret,
52
+ { expiresIn: this.config.refreshExpiry }
53
+ );
54
+ return { access_token, refresh_token, sid };
55
+ }
56
+ verifyToken(token) {
57
+ try {
58
+ return jwt.verify(token, this.config.secret);
59
+ } catch (error) {
60
+ if (error.name === "TokenExpiredError") {
61
+ return { error: "expired", message: "Token has expired" };
40
62
  }
41
- };
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" });
63
+ return { error: "invalid", message: error.message };
64
+ }
65
+ }
66
+ // --------------------------------------------------
67
+ // 👁️ CORE 2: BIOMETRICS & PASSKEYS (World-Class Security)
68
+ // --------------------------------------------------
69
+ async generatePasskeyOptions(userId, userEmail, rpID = "navojit.com") {
70
+ return generateRegistrationOptions({
71
+ rpName: "Navojit Ecosystem",
72
+ rpID,
73
+ userID: Buffer.from(userId),
74
+ userName: userEmail,
75
+ attestationType: "none",
76
+ authenticatorSelection: {
77
+ residentKey: "required",
78
+ userVerification: "preferred"
58
79
  }
59
80
  });
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" };
69
- });
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"
81
+ }
82
+ async verifyPasskey(expectedChallenge, responseBody, origin, rpID = "navojit.com") {
83
+ try {
84
+ const verification = await verifyRegistrationResponse({
85
+ response: responseBody,
86
+ expectedChallenge,
87
+ expectedOrigin: origin,
88
+ expectedRPID: rpID
89
+ });
90
+ return verification;
91
+ } catch (error) {
92
+ return { verified: false, error: error.message };
93
+ }
94
+ }
95
+ // --------------------------------------------------
96
+ // 🔐 CORE 3: ARGON2 & OTP LOGIC
97
+ // --------------------------------------------------
98
+ async hashPassword(password) {
99
+ return await argon2.hash(password);
100
+ }
101
+ async verifyPassword(hash2, password) {
102
+ return await argon2.verify(hash2, password);
103
+ }
104
+ async verifyAndFetchUser(email, otp) {
105
+ if (!otp || otp.length < 4) throw new Error("Invalid OTP");
106
+ let user = await this.config.adapter.findUserByEmail(email);
107
+ if (!user) {
108
+ user = await this.config.adapter.createUser({
109
+ email,
110
+ password: await this.hashPassword("NAV_SECURE_" + uuidv4()),
111
+ role: "member",
112
+ isVerified: true
113
+ });
114
+ }
115
+ return user;
116
+ }
117
+ // ==========================================
118
+ // 3. THE CONNECTORS (Purane Features Wapas!)
119
+ // ==========================================
120
+ /**
121
+ * 🟢 FASTIFY CONNECTOR
122
+ */
123
+ async attach(server) {
124
+ const { prefix, adapter } = this.config;
125
+ server.post(`${prefix}/otp/verify`, async (req, reply) => {
126
+ try {
127
+ const user = await this.verifyAndFetchUser(
128
+ req.body.email,
129
+ req.body.otp
130
+ );
131
+ const tokens = this.generateOmniTokens(user, {
132
+ mfa_v: true,
133
+ am: ["otp"]
79
134
  });
135
+ return { success: true, ...tokens, gateway: "navojit-v4-fastify" };
136
+ } catch (e) {
137
+ return reply.code(400).send({ error: e.message });
80
138
  }
81
- const sessionId = uuidv4();
82
- const token = server.jwt.sign({
83
- sub: user.id,
84
- email: user.email,
85
- role: user.role,
86
- orgId: user.orgId,
87
- sid: sessionId
88
- });
89
- await trackSession(user.id, sessionId);
90
- return { success: true, token, message: "Welcome to Navojit Ecosystem!" };
91
139
  });
92
- server.post(`${prefix}/login`, async (request, reply) => {
93
- const { email, password } = request.body;
94
- const user = await adapter.findUserByEmail(email);
95
- if (!user || !await argon2.verify(user.password, password)) {
96
- return reply.code(401).send({ error: "Invalid credentials" });
140
+ server.addHook("preHandler", async (req, reply) => {
141
+ if (req.routerPath.startsWith(`${prefix}/profile`)) {
142
+ const token = req.headers.authorization?.split(" ")[1];
143
+ if (!token) return reply.code(401).send({ error: "Missing Token" });
144
+ const decoded = this.verifyToken(token);
145
+ if (decoded.error)
146
+ return reply.code(401).send({ error: decoded.error });
147
+ req.user = decoded;
97
148
  }
98
- const sessionId = uuidv4();
99
- const token = server.jwt.sign({
100
- sub: user.id,
101
- email: user.email,
102
- role: user.role,
103
- orgId: user.orgId,
104
- sid: sessionId
105
- });
106
- await trackSession(user.id, sessionId);
107
- return { success: true, token };
108
149
  });
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}` };
150
+ server.get(`${prefix}/profile`, async (req, reply) => {
151
+ const user = await adapter.findUserById(req.user.sub);
152
+ return {
153
+ success: true,
154
+ user: { id: user.id, email: user.email, role: user.role }
155
+ };
156
+ });
157
+ }
158
+ /**
159
+ * 🔵 EXPRESS CONNECTOR
160
+ */
161
+ express() {
162
+ const express = __require("express");
163
+ const router = express.Router();
164
+ const { prefix, adapter } = this.config;
165
+ router.post(`${prefix}/otp/verify`, async (req, res) => {
166
+ try {
167
+ const user = await this.verifyAndFetchUser(
168
+ req.body.email,
169
+ req.body.otp
170
+ );
171
+ const tokens = this.generateOmniTokens(user, {
172
+ mfa_v: true,
173
+ am: ["otp"]
174
+ });
175
+ res.json({ success: true, ...tokens, gateway: "navojit-v4-express" });
176
+ } catch (e) {
177
+ res.status(400).json({ error: e.message });
178
+ }
122
179
  });
180
+ return router;
181
+ }
182
+ };
183
+ var MongooseAdapter = class {
184
+ constructor(model) {
185
+ this.model = model;
186
+ }
187
+ model;
188
+ async findUserByEmail(email) {
189
+ return await this.model.findOne({ email });
190
+ }
191
+ async findUserById(id) {
192
+ return await this.model.findById(id);
193
+ }
194
+ async createUser(data) {
195
+ return await new this.model(data).save();
123
196
  }
124
197
  };
125
198
  export {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "navojit-auth",
3
- "version": "1.6.2",
4
- "description": "Ultimate Authentication Engine for Fastify and Mongoose, supporting OTP, Passkeys, and Multi-tenancy.",
3
+ "version": "4.0.0",
4
+ "description": "The World's Smartest Universal Auth Engine. Supports Passkeys, Fastify, Mongoose, Drizzle, and Cross-Language Sync.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
7
7
  "types": "./dist/index.d.ts",
@@ -17,7 +17,7 @@
17
17
  ],
18
18
  "scripts": {
19
19
  "dev": "tsx watch src/index.ts",
20
- "build": "tsup src/index.ts --format cjs,esm --dts --clean",
20
+ "build": "tsup src/index.ts --format cjs,esm --dts --clean --external express",
21
21
  "prepublishOnly": "npm run build",
22
22
  "lint": "tsc",
23
23
  "test": "vitest run",
@@ -30,7 +30,8 @@
30
30
  "mongoose",
31
31
  "mongodb",
32
32
  "multi-tenant",
33
- "universal-auth"
33
+ "universal-auth",
34
+ "passkeys"
34
35
  ],
35
36
  "author": "Kashish Singh",
36
37
  "license": "MIT",
@@ -49,12 +50,15 @@
49
50
  "argon2": "^0.44.0",
50
51
  "dotenv": "^17.4.1",
51
52
  "google-auth-library": "^10.6.2",
53
+ "jsonwebtoken": "^9.0.2",
52
54
  "resend": "^6.10.0",
53
55
  "uuid": "^13.0.0",
54
56
  "zod": "^4.3.6"
55
57
  },
56
58
  "devDependencies": {
57
- "@types/node": "^22.0.0",
59
+ "@types/jsonwebtoken": "^9.0.10",
60
+ "@types/node": "^22.19.17",
61
+ "@types/uuid": "^10.0.0",
58
62
  "@vitest/coverage-v8": "^4.1.4",
59
63
  "drizzle-orm": "^0.30.0",
60
64
  "fastify": "^4.26.2",
@@ -64,4 +68,4 @@
64
68
  "typescript": "^5.7.0",
65
69
  "vitest": "^4.1.4"
66
70
  }
67
- }
71
+ }