navojit-auth 2.0.0 → 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 +21 -31
- package/dist/index.d.ts +21 -31
- package/dist/index.js +143 -61
- package/dist/index.mjs +153 -61
- package/package.json +10 -6
package/dist/index.d.mts
CHANGED
|
@@ -1,23 +1,5 @@
|
|
|
1
1
|
import { FastifyInstance } from 'fastify';
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* 1. UNIVERSAL JWT TYPES
|
|
5
|
-
*/
|
|
6
|
-
declare module "@fastify/jwt" {
|
|
7
|
-
interface FastifyJWT {
|
|
8
|
-
payload: {
|
|
9
|
-
sub: string;
|
|
10
|
-
email: string;
|
|
11
|
-
role: string;
|
|
12
|
-
orgId?: string;
|
|
13
|
-
sid?: string;
|
|
14
|
-
impersonatedBy?: string;
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* 2. THE CONTRACTS (Interfaces)
|
|
20
|
-
*/
|
|
21
3
|
interface AuthAdapter {
|
|
22
4
|
createUser(data: any): Promise<any>;
|
|
23
5
|
findUserByEmail(email: string): Promise<any>;
|
|
@@ -26,29 +8,37 @@ interface AuthAdapter {
|
|
|
26
8
|
interface AuthConfig {
|
|
27
9
|
adapter: AuthAdapter;
|
|
28
10
|
secret: string;
|
|
29
|
-
redisClient?: any;
|
|
30
11
|
prefix?: string;
|
|
12
|
+
accessExpiry?: string;
|
|
13
|
+
refreshExpiry?: string;
|
|
14
|
+
}
|
|
15
|
+
interface OmniTokens {
|
|
16
|
+
access_token: string;
|
|
17
|
+
refresh_token: string;
|
|
18
|
+
sid: string;
|
|
31
19
|
}
|
|
32
|
-
/**
|
|
33
|
-
* 4. FRAMEWORK HANDLERS
|
|
34
|
-
*/
|
|
35
20
|
declare class NavojitAuth {
|
|
36
|
-
private engine;
|
|
37
21
|
private config;
|
|
38
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>;
|
|
39
33
|
/**
|
|
40
|
-
*
|
|
34
|
+
* 🟢 FASTIFY CONNECTOR
|
|
41
35
|
*/
|
|
42
36
|
attach(server: FastifyInstance): Promise<void>;
|
|
43
37
|
/**
|
|
44
|
-
*
|
|
45
|
-
* Iska use karke Express developers bhi aapka package use kar payenge.
|
|
38
|
+
* 🔵 EXPRESS CONNECTOR
|
|
46
39
|
*/
|
|
47
|
-
express():
|
|
40
|
+
express(): any;
|
|
48
41
|
}
|
|
49
|
-
/**
|
|
50
|
-
* 5. DATABASE ADAPTERS
|
|
51
|
-
*/
|
|
52
42
|
declare class MongooseAdapter implements AuthAdapter {
|
|
53
43
|
private model;
|
|
54
44
|
constructor(model: any);
|
|
@@ -57,4 +47,4 @@ declare class MongooseAdapter implements AuthAdapter {
|
|
|
57
47
|
createUser(data: any): Promise<any>;
|
|
58
48
|
}
|
|
59
49
|
|
|
60
|
-
export { type AuthAdapter, type AuthConfig, MongooseAdapter, NavojitAuth };
|
|
50
|
+
export { type AuthAdapter, type AuthConfig, MongooseAdapter, NavojitAuth, type OmniTokens };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,23 +1,5 @@
|
|
|
1
1
|
import { FastifyInstance } from 'fastify';
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* 1. UNIVERSAL JWT TYPES
|
|
5
|
-
*/
|
|
6
|
-
declare module "@fastify/jwt" {
|
|
7
|
-
interface FastifyJWT {
|
|
8
|
-
payload: {
|
|
9
|
-
sub: string;
|
|
10
|
-
email: string;
|
|
11
|
-
role: string;
|
|
12
|
-
orgId?: string;
|
|
13
|
-
sid?: string;
|
|
14
|
-
impersonatedBy?: string;
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* 2. THE CONTRACTS (Interfaces)
|
|
20
|
-
*/
|
|
21
3
|
interface AuthAdapter {
|
|
22
4
|
createUser(data: any): Promise<any>;
|
|
23
5
|
findUserByEmail(email: string): Promise<any>;
|
|
@@ -26,29 +8,37 @@ interface AuthAdapter {
|
|
|
26
8
|
interface AuthConfig {
|
|
27
9
|
adapter: AuthAdapter;
|
|
28
10
|
secret: string;
|
|
29
|
-
redisClient?: any;
|
|
30
11
|
prefix?: string;
|
|
12
|
+
accessExpiry?: string;
|
|
13
|
+
refreshExpiry?: string;
|
|
14
|
+
}
|
|
15
|
+
interface OmniTokens {
|
|
16
|
+
access_token: string;
|
|
17
|
+
refresh_token: string;
|
|
18
|
+
sid: string;
|
|
31
19
|
}
|
|
32
|
-
/**
|
|
33
|
-
* 4. FRAMEWORK HANDLERS
|
|
34
|
-
*/
|
|
35
20
|
declare class NavojitAuth {
|
|
36
|
-
private engine;
|
|
37
21
|
private config;
|
|
38
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>;
|
|
39
33
|
/**
|
|
40
|
-
*
|
|
34
|
+
* 🟢 FASTIFY CONNECTOR
|
|
41
35
|
*/
|
|
42
36
|
attach(server: FastifyInstance): Promise<void>;
|
|
43
37
|
/**
|
|
44
|
-
*
|
|
45
|
-
* Iska use karke Express developers bhi aapka package use kar payenge.
|
|
38
|
+
* 🔵 EXPRESS CONNECTOR
|
|
46
39
|
*/
|
|
47
|
-
express():
|
|
40
|
+
express(): any;
|
|
48
41
|
}
|
|
49
|
-
/**
|
|
50
|
-
* 5. DATABASE ADAPTERS
|
|
51
|
-
*/
|
|
52
42
|
declare class MongooseAdapter implements AuthAdapter {
|
|
53
43
|
private model;
|
|
54
44
|
constructor(model: any);
|
|
@@ -57,4 +47,4 @@ declare class MongooseAdapter implements AuthAdapter {
|
|
|
57
47
|
createUser(data: any): Promise<any>;
|
|
58
48
|
}
|
|
59
49
|
|
|
60
|
-
export { type AuthAdapter, type AuthConfig, MongooseAdapter, NavojitAuth };
|
|
50
|
+
export { type AuthAdapter, type AuthConfig, MongooseAdapter, NavojitAuth, type OmniTokens };
|
package/dist/index.js
CHANGED
|
@@ -34,91 +34,175 @@ __export(index_exports, {
|
|
|
34
34
|
NavojitAuth: () => NavojitAuth
|
|
35
35
|
});
|
|
36
36
|
module.exports = __toCommonJS(index_exports);
|
|
37
|
-
var
|
|
37
|
+
var import_jsonwebtoken = __toESM(require("jsonwebtoken"));
|
|
38
38
|
var import_uuid = require("uuid");
|
|
39
|
-
var
|
|
39
|
+
var import_server = require("@simplewebauthn/server");
|
|
40
|
+
var argon2 = __toESM(require("argon2"));
|
|
41
|
+
var NavojitAuth = class {
|
|
42
|
+
config;
|
|
40
43
|
constructor(config) {
|
|
41
|
-
this.config =
|
|
44
|
+
this.config = {
|
|
45
|
+
prefix: "/auth",
|
|
46
|
+
accessExpiry: "15m",
|
|
47
|
+
refreshExpiry: "30d",
|
|
48
|
+
...config
|
|
49
|
+
};
|
|
42
50
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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" };
|
|
87
|
+
}
|
|
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"
|
|
104
|
+
}
|
|
51
105
|
});
|
|
52
106
|
}
|
|
53
|
-
async
|
|
54
|
-
|
|
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");
|
|
55
131
|
let user = await this.config.adapter.findUserByEmail(email);
|
|
56
132
|
if (!user) {
|
|
57
133
|
user = await this.config.adapter.createUser({
|
|
58
134
|
email,
|
|
59
|
-
password: "
|
|
60
|
-
role: "member"
|
|
135
|
+
password: await this.hashPassword("NAV_SECURE_" + (0, import_uuid.v4)()),
|
|
136
|
+
role: "member",
|
|
137
|
+
isVerified: true
|
|
61
138
|
});
|
|
62
139
|
}
|
|
63
140
|
return user;
|
|
64
141
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
config;
|
|
69
|
-
constructor(config) {
|
|
70
|
-
this.config = { prefix: "/auth", ...config };
|
|
71
|
-
this.engine = new NavojitEngine(this.config);
|
|
72
|
-
}
|
|
142
|
+
// ==========================================
|
|
143
|
+
// 3. THE CONNECTORS (Purane Features Wapas!)
|
|
144
|
+
// ==========================================
|
|
73
145
|
/**
|
|
74
|
-
*
|
|
146
|
+
* 🟢 FASTIFY CONNECTOR
|
|
75
147
|
*/
|
|
76
148
|
async attach(server) {
|
|
77
|
-
const { prefix,
|
|
78
|
-
|
|
79
|
-
server.register(import_jwt.default, { secret });
|
|
80
|
-
}
|
|
81
|
-
server.get(`${prefix}/profile`, async (request, reply) => {
|
|
82
|
-
try {
|
|
83
|
-
const decoded = await request.jwtVerify();
|
|
84
|
-
const user = await this.config.adapter.findUserById(decoded.sub);
|
|
85
|
-
return {
|
|
86
|
-
success: true,
|
|
87
|
-
user: { id: user.id, email: user.email, role: user.role }
|
|
88
|
-
};
|
|
89
|
-
} catch (e) {
|
|
90
|
-
return reply.code(401).send({ error: "Unauthorized" });
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
server.post(`${prefix}/otp/verify`, async (request, reply) => {
|
|
149
|
+
const { prefix, adapter } = this.config;
|
|
150
|
+
server.post(`${prefix}/otp/verify`, async (req, reply) => {
|
|
94
151
|
try {
|
|
95
|
-
const user = await this.
|
|
96
|
-
|
|
97
|
-
|
|
152
|
+
const user = await this.verifyAndFetchUser(
|
|
153
|
+
req.body.email,
|
|
154
|
+
req.body.otp
|
|
98
155
|
);
|
|
99
|
-
const
|
|
100
|
-
|
|
156
|
+
const tokens = this.generateOmniTokens(user, {
|
|
157
|
+
mfa_v: true,
|
|
158
|
+
am: ["otp"]
|
|
159
|
+
});
|
|
160
|
+
return { success: true, ...tokens, gateway: "navojit-v4-fastify" };
|
|
101
161
|
} catch (e) {
|
|
102
162
|
return reply.code(400).send({ error: e.message });
|
|
103
163
|
}
|
|
104
164
|
});
|
|
105
|
-
server.
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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;
|
|
173
|
+
}
|
|
174
|
+
});
|
|
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
|
+
};
|
|
111
181
|
});
|
|
112
182
|
}
|
|
113
183
|
/**
|
|
114
|
-
*
|
|
115
|
-
* Iska use karke Express developers bhi aapka package use kar payenge.
|
|
184
|
+
* 🔵 EXPRESS CONNECTOR
|
|
116
185
|
*/
|
|
117
186
|
express() {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
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
|
+
}
|
|
204
|
+
});
|
|
205
|
+
return router;
|
|
122
206
|
}
|
|
123
207
|
};
|
|
124
208
|
var MongooseAdapter = class {
|
|
@@ -133,9 +217,7 @@ var MongooseAdapter = class {
|
|
|
133
217
|
return await this.model.findById(id);
|
|
134
218
|
}
|
|
135
219
|
async createUser(data) {
|
|
136
|
-
|
|
137
|
-
await user.save();
|
|
138
|
-
return user;
|
|
220
|
+
return await new this.model(data).save();
|
|
139
221
|
}
|
|
140
222
|
};
|
|
141
223
|
// Annotate the CommonJS export names for ESM import in node:
|
package/dist/index.mjs
CHANGED
|
@@ -1,89 +1,183 @@
|
|
|
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 "
|
|
9
|
+
import jwt from "jsonwebtoken";
|
|
3
10
|
import { v4 as uuidv4 } from "uuid";
|
|
4
|
-
|
|
11
|
+
import {
|
|
12
|
+
generateRegistrationOptions,
|
|
13
|
+
verifyRegistrationResponse
|
|
14
|
+
} from "@simplewebauthn/server";
|
|
15
|
+
import * as argon2 from "argon2";
|
|
16
|
+
var NavojitAuth = class {
|
|
17
|
+
config;
|
|
5
18
|
constructor(config) {
|
|
6
|
-
this.config =
|
|
19
|
+
this.config = {
|
|
20
|
+
prefix: "/auth",
|
|
21
|
+
accessExpiry: "15m",
|
|
22
|
+
refreshExpiry: "30d",
|
|
23
|
+
...config
|
|
24
|
+
};
|
|
7
25
|
}
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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" };
|
|
62
|
+
}
|
|
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"
|
|
79
|
+
}
|
|
16
80
|
});
|
|
17
81
|
}
|
|
18
|
-
async
|
|
19
|
-
|
|
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");
|
|
20
106
|
let user = await this.config.adapter.findUserByEmail(email);
|
|
21
107
|
if (!user) {
|
|
22
108
|
user = await this.config.adapter.createUser({
|
|
23
109
|
email,
|
|
24
|
-
password: "
|
|
25
|
-
role: "member"
|
|
110
|
+
password: await this.hashPassword("NAV_SECURE_" + uuidv4()),
|
|
111
|
+
role: "member",
|
|
112
|
+
isVerified: true
|
|
26
113
|
});
|
|
27
114
|
}
|
|
28
115
|
return user;
|
|
29
116
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
config;
|
|
34
|
-
constructor(config) {
|
|
35
|
-
this.config = { prefix: "/auth", ...config };
|
|
36
|
-
this.engine = new NavojitEngine(this.config);
|
|
37
|
-
}
|
|
117
|
+
// ==========================================
|
|
118
|
+
// 3. THE CONNECTORS (Purane Features Wapas!)
|
|
119
|
+
// ==========================================
|
|
38
120
|
/**
|
|
39
|
-
*
|
|
121
|
+
* 🟢 FASTIFY CONNECTOR
|
|
40
122
|
*/
|
|
41
123
|
async attach(server) {
|
|
42
|
-
const { prefix,
|
|
43
|
-
|
|
44
|
-
server.register(jwt, { secret });
|
|
45
|
-
}
|
|
46
|
-
server.get(`${prefix}/profile`, async (request, reply) => {
|
|
47
|
-
try {
|
|
48
|
-
const decoded = await request.jwtVerify();
|
|
49
|
-
const user = await this.config.adapter.findUserById(decoded.sub);
|
|
50
|
-
return {
|
|
51
|
-
success: true,
|
|
52
|
-
user: { id: user.id, email: user.email, role: user.role }
|
|
53
|
-
};
|
|
54
|
-
} catch (e) {
|
|
55
|
-
return reply.code(401).send({ error: "Unauthorized" });
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
server.post(`${prefix}/otp/verify`, async (request, reply) => {
|
|
124
|
+
const { prefix, adapter } = this.config;
|
|
125
|
+
server.post(`${prefix}/otp/verify`, async (req, reply) => {
|
|
59
126
|
try {
|
|
60
|
-
const user = await this.
|
|
61
|
-
|
|
62
|
-
|
|
127
|
+
const user = await this.verifyAndFetchUser(
|
|
128
|
+
req.body.email,
|
|
129
|
+
req.body.otp
|
|
63
130
|
);
|
|
64
|
-
const
|
|
65
|
-
|
|
131
|
+
const tokens = this.generateOmniTokens(user, {
|
|
132
|
+
mfa_v: true,
|
|
133
|
+
am: ["otp"]
|
|
134
|
+
});
|
|
135
|
+
return { success: true, ...tokens, gateway: "navojit-v4-fastify" };
|
|
66
136
|
} catch (e) {
|
|
67
137
|
return reply.code(400).send({ error: e.message });
|
|
68
138
|
}
|
|
69
139
|
});
|
|
70
|
-
server.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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;
|
|
148
|
+
}
|
|
149
|
+
});
|
|
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
|
+
};
|
|
76
156
|
});
|
|
77
157
|
}
|
|
78
158
|
/**
|
|
79
|
-
*
|
|
80
|
-
* Iska use karke Express developers bhi aapka package use kar payenge.
|
|
159
|
+
* 🔵 EXPRESS CONNECTOR
|
|
81
160
|
*/
|
|
82
161
|
express() {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
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
|
+
}
|
|
179
|
+
});
|
|
180
|
+
return router;
|
|
87
181
|
}
|
|
88
182
|
};
|
|
89
183
|
var MongooseAdapter = class {
|
|
@@ -98,9 +192,7 @@ var MongooseAdapter = class {
|
|
|
98
192
|
return await this.model.findById(id);
|
|
99
193
|
}
|
|
100
194
|
async createUser(data) {
|
|
101
|
-
|
|
102
|
-
await user.save();
|
|
103
|
-
return user;
|
|
195
|
+
return await new this.model(data).save();
|
|
104
196
|
}
|
|
105
197
|
};
|
|
106
198
|
export {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "navojit-auth",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
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/
|
|
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
|
+
}
|