secure-auth-kit 1.0.1
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/constants/index.d.ts +9 -0
- package/dist/constants/index.d.ts.map +1 -0
- package/dist/constants/index.js +9 -0
- package/dist/constants/index.js.map +1 -0
- package/dist/core/middleware/error.middleware.d.ts +3 -0
- package/dist/core/middleware/error.middleware.d.ts.map +1 -0
- package/dist/core/middleware/error.middleware.js +12 -0
- package/dist/core/middleware/error.middleware.js.map +1 -0
- package/dist/core/routes/auth.routes.d.ts +3 -0
- package/dist/core/routes/auth.routes.d.ts.map +1 -0
- package/dist/core/routes/auth.routes.js +15 -0
- package/dist/core/routes/auth.routes.js.map +1 -0
- package/dist/core/stores/config.store.d.ts +4 -0
- package/dist/core/stores/config.store.d.ts.map +1 -0
- package/dist/core/stores/config.store.js +12 -0
- package/dist/core/stores/config.store.js.map +1 -0
- package/dist/features/login/login.controller.d.ts +3 -0
- package/dist/features/login/login.controller.d.ts.map +1 -0
- package/dist/features/login/login.controller.js +16 -0
- package/dist/features/login/login.controller.js.map +1 -0
- package/dist/features/login/login.service.d.ts +4 -0
- package/dist/features/login/login.service.d.ts.map +1 -0
- package/dist/features/login/login.service.js +20 -0
- package/dist/features/login/login.service.js.map +1 -0
- package/dist/features/login/login.validator.d.ts +3 -0
- package/dist/features/login/login.validator.d.ts.map +1 -0
- package/dist/features/login/login.validator.js +15 -0
- package/dist/features/login/login.validator.js.map +1 -0
- package/dist/features/me/me.controller.d.ts +3 -0
- package/dist/features/me/me.controller.d.ts.map +1 -0
- package/dist/features/me/me.controller.js +21 -0
- package/dist/features/me/me.controller.js.map +1 -0
- package/dist/features/register/register.controller.d.ts +3 -0
- package/dist/features/register/register.controller.d.ts.map +1 -0
- package/dist/features/register/register.controller.js +16 -0
- package/dist/features/register/register.controller.js.map +1 -0
- package/dist/features/register/register.service.d.ts +4 -0
- package/dist/features/register/register.service.d.ts.map +1 -0
- package/dist/features/register/register.service.js +24 -0
- package/dist/features/register/register.service.js.map +1 -0
- package/dist/features/register/register.validator.d.ts +3 -0
- package/dist/features/register/register.validator.d.ts.map +1 -0
- package/dist/features/register/register.validator.js +34 -0
- package/dist/features/register/register.validator.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/authenticate.middleware.d.ts +4 -0
- package/dist/middleware/authenticate.middleware.d.ts.map +1 -0
- package/dist/middleware/authenticate.middleware.js +28 -0
- package/dist/middleware/authenticate.middleware.js.map +1 -0
- package/dist/types/auth.types.d.ts +32 -0
- package/dist/types/auth.types.d.ts.map +1 -0
- package/dist/types/auth.types.js +2 -0
- package/dist/types/auth.types.js.map +1 -0
- package/dist/types/config.types.d.ts +13 -0
- package/dist/types/config.types.d.ts.map +1 -0
- package/dist/types/config.types.js +2 -0
- package/dist/types/config.types.js.map +1 -0
- package/dist/types/jwt.types.d.ts +12 -0
- package/dist/types/jwt.types.d.ts.map +1 -0
- package/dist/types/jwt.types.js +2 -0
- package/dist/types/jwt.types.js.map +1 -0
- package/dist/utils/AppError.d.ts +12 -0
- package/dist/utils/AppError.d.ts.map +1 -0
- package/dist/utils/AppError.js +30 -0
- package/dist/utils/AppError.js.map +1 -0
- package/dist/utils/hash.d.ts +3 -0
- package/dist/utils/hash.d.ts.map +1 -0
- package/dist/utils/hash.js +9 -0
- package/dist/utils/hash.js.map +1 -0
- package/dist/utils/jwt.d.ts +5 -0
- package/dist/utils/jwt.d.ts.map +1 -0
- package/dist/utils/jwt.js +27 -0
- package/dist/utils/jwt.js.map +1 -0
- package/dist/utils/response.d.ts +17 -0
- package/dist/utils/response.d.ts.map +1 -0
- package/dist/utils/response.js +20 -0
- package/dist/utils/response.js.map +1 -0
- package/dist/utils/sanitizeUser.d.ts +4 -0
- package/dist/utils/sanitizeUser.d.ts.map +1 -0
- package/dist/utils/sanitizeUser.js +17 -0
- package/dist/utils/sanitizeUser.js.map +1 -0
- package/package.json +49 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const SALT_ROUNDS = 10;
|
|
2
|
+
export declare const SENSITIVE_FIELDS: Set<string>;
|
|
3
|
+
export declare const EMAIL_REGEX: RegExp;
|
|
4
|
+
export declare const MIN_PASSWORD_LENGTH = 8;
|
|
5
|
+
export declare const PASSWORD_UPPERCASE_REGEX: RegExp;
|
|
6
|
+
export declare const PASSWORD_LOWERCASE_REGEX: RegExp;
|
|
7
|
+
export declare const PASSWORD_NUMBER_REGEX: RegExp;
|
|
8
|
+
export declare const PASSWORD_SPECIAL_CHARACTER_REGEX: RegExp;
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/constants/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,KAAK,CAAC;AAE9B,eAAO,MAAM,gBAAgB,aAA+B,CAAC;AAE7D,eAAO,MAAM,WAAW,QAA+B,CAAC;AAExD,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC,eAAO,MAAM,wBAAwB,QAAU,CAAC;AAEhD,eAAO,MAAM,wBAAwB,QAAU,CAAC;AAEhD,eAAO,MAAM,qBAAqB,QAAO,CAAC;AAE1C,eAAO,MAAM,gCAAgC,QAAc,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const SALT_ROUNDS = 10;
|
|
2
|
+
export const SENSITIVE_FIELDS = new Set(['password', '__v']);
|
|
3
|
+
export const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
4
|
+
export const MIN_PASSWORD_LENGTH = 8;
|
|
5
|
+
export const PASSWORD_UPPERCASE_REGEX = /[A-Z]/;
|
|
6
|
+
export const PASSWORD_LOWERCASE_REGEX = /[a-z]/;
|
|
7
|
+
export const PASSWORD_NUMBER_REGEX = /\d/;
|
|
8
|
+
export const PASSWORD_SPECIAL_CHARACTER_REGEX = /[@$!%*?&]/;
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/constants/index.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG,EAAE,CAAC;AAE9B,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC;AAE7D,MAAM,CAAC,MAAM,WAAW,GAAG,4BAA4B,CAAC;AAExD,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAErC,MAAM,CAAC,MAAM,wBAAwB,GAAG,OAAO,CAAC;AAEhD,MAAM,CAAC,MAAM,wBAAwB,GAAG,OAAO,CAAC;AAEhD,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAI,CAAC;AAE1C,MAAM,CAAC,MAAM,gCAAgC,GAAG,WAAW,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error.middleware.d.ts","sourceRoot":"","sources":["../../../src/core/middleware/error.middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAI1D,wBAAgB,eAAe,CAAC,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CASjG"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AppError } from '../../utils/AppError.js';
|
|
2
|
+
import { sendError } from '../../utils/response.js';
|
|
3
|
+
export function errorMiddleware(err, req, res, next) {
|
|
4
|
+
if (err instanceof AppError && err.isOperational) {
|
|
5
|
+
sendError(res, err.message, err.statusCode, err.code);
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
// Unknown Errors
|
|
9
|
+
console.error('[secure-auth-kit] Unhandled error', err);
|
|
10
|
+
sendError(res, 'An unexpected error occurred', 500, 'INTERNAL_ERROR');
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=error.middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error.middleware.js","sourceRoot":"","sources":["../../../src/core/middleware/error.middleware.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEpD,MAAM,UAAU,eAAe,CAAC,GAAU,EAAE,GAAY,EAAE,GAAa,EAAE,IAAkB;IACvF,IAAI,GAAG,YAAY,QAAQ,IAAI,GAAG,CAAC,aAAa,EAAE,CAAC;QAC/C,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QACtD,OAAO;IACX,CAAC;IAED,iBAAiB;IACjB,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,GAAG,CAAC,CAAC;IACxD,SAAS,CAAC,GAAG,EAAE,8BAA8B,EAAE,GAAG,EAAE,gBAAgB,CAAC,CAAC;AAC1E,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.routes.d.ts","sourceRoot":"","sources":["../../../src/core/routes/auth.routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAMjC,eAAO,MAAM,gBAAgB,QAAO,MAWnC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { loginController } from '../../features/login/login.controller.js';
|
|
3
|
+
import { meController } from '../../features/me/me.controller.js';
|
|
4
|
+
import { registerController } from '../../features/register/register.controller.js';
|
|
5
|
+
import { authenticate } from '../../middleware/authenticate.middleware.js';
|
|
6
|
+
export const createAuthRouter = () => {
|
|
7
|
+
const router = Router();
|
|
8
|
+
// Public routes
|
|
9
|
+
router.post('/register', registerController);
|
|
10
|
+
router.post('/login', loginController);
|
|
11
|
+
// Protected routes
|
|
12
|
+
router.get('/me', authenticate, meController);
|
|
13
|
+
return router;
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=auth.routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.routes.js","sourceRoot":"","sources":["../../../src/core/routes/auth.routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,MAAM,0CAA0C,CAAC;AAC3E,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,MAAM,gDAAgD,CAAC;AACpF,OAAO,EAAE,YAAY,EAAE,MAAM,6CAA6C,CAAC;AAE3E,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAW,EAAE;IACzC,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IAExB,gBAAgB;IAChB,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,kBAAkB,CAAC,CAAC;IAC7C,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;IAEvC,mBAAmB;IACnB,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,YAAY,EAAE,YAAY,CAAC,CAAC;IAE9C,OAAO,MAAM,CAAC;AAClB,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.store.d.ts","sourceRoot":"","sources":["../../../src/core/stores/config.store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAK/D,wBAAgB,SAAS,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAExD;AAED,wBAAgB,SAAS,IAAI,gBAAgB,CAQ5C"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AppError } from '../../utils/AppError.js';
|
|
2
|
+
let _config = null;
|
|
3
|
+
export function setConfig(config) {
|
|
4
|
+
_config = config;
|
|
5
|
+
}
|
|
6
|
+
export function getConfig() {
|
|
7
|
+
if (!_config) {
|
|
8
|
+
throw AppError.internal('secure-auth-kit: config has not been initialized. Call secureAuth() first.');
|
|
9
|
+
}
|
|
10
|
+
return _config;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=config.store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.store.js","sourceRoot":"","sources":["../../../src/core/stores/config.store.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAEnD,IAAI,OAAO,GAA4B,IAAI,CAAC;AAE5C,MAAM,UAAU,SAAS,CAAC,MAAwB;IAC9C,OAAO,GAAG,MAAM,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,SAAS;IACrB,IAAI,CAAC,OAAO,EAAE,CAAC;QACX,MAAM,QAAQ,CAAC,QAAQ,CACnB,4EAA4E,CAC/E,CAAC;IACN,CAAC;IAED,OAAO,OAAO,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.controller.d.ts","sourceRoot":"","sources":["../../../src/features/login/login.controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAM1D,eAAO,MAAM,eAAe,GACxB,KAAK,OAAO,EACZ,KAAK,QAAQ,EACb,MAAM,YAAY,KACnB,OAAO,CAAC,IAAI,CAUd,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { getConfig } from '../../core/stores/config.store.js';
|
|
2
|
+
import { sendSuccess } from '../../utils/response.js';
|
|
3
|
+
import { validateRegisterInput } from '../register/register.validator.js';
|
|
4
|
+
import { loginUser } from './login.service.js';
|
|
5
|
+
export const loginController = async (req, res, next) => {
|
|
6
|
+
try {
|
|
7
|
+
const input = validateRegisterInput(req.body);
|
|
8
|
+
const config = getConfig();
|
|
9
|
+
const result = await loginUser(input, config);
|
|
10
|
+
sendSuccess(res, result, 'Login successful');
|
|
11
|
+
}
|
|
12
|
+
catch (err) {
|
|
13
|
+
next(err);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=login.controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.controller.js","sourceRoot":"","sources":["../../../src/features/login/login.controller.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,EAChC,GAAY,EACZ,GAAa,EACb,IAAkB,EACL,EAAE;IACf,IAAI,CAAC;QACD,MAAM,KAAK,GAAG,qBAAqB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC9C,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAE9C,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,kBAAkB,CAAC,CAAC;IACjD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,IAAI,CAAC,GAAG,CAAC,CAAC;IACd,CAAC;AACL,CAAC,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { LoginInput, LoginResult } from '../../types/auth.types.js';
|
|
2
|
+
import { SecureAuthConfig } from '../../types/config.types.js';
|
|
3
|
+
export declare const loginUser: (input: LoginInput, config: SecureAuthConfig) => Promise<LoginResult>;
|
|
4
|
+
//# sourceMappingURL=login.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.service.d.ts","sourceRoot":"","sources":["../../../src/features/login/login.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAM/D,eAAO,MAAM,SAAS,GAClB,OAAO,UAAU,EACjB,QAAQ,gBAAgB,KACzB,OAAO,CAAC,WAAW,CAkBrB,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { AppError } from '../../utils/AppError.js';
|
|
2
|
+
import { comparePassword } from '../../utils/hash.js';
|
|
3
|
+
import { generateAccessToken, generateRefreshToken } from '../../utils/jwt.js';
|
|
4
|
+
import { sanitizeUser } from '../../utils/sanitizeUser.js';
|
|
5
|
+
export const loginUser = async (input, config) => {
|
|
6
|
+
const { userModel, jwt: jwtConfig } = config;
|
|
7
|
+
const user = await userModel.findOne({ email: input.email }).select('+password');
|
|
8
|
+
if (!user) {
|
|
9
|
+
throw AppError.unauthorized('Invalid email or password', 'INVALID_CREDENTIALS');
|
|
10
|
+
}
|
|
11
|
+
const isMatch = await comparePassword(input.password, user.password);
|
|
12
|
+
if (!isMatch) {
|
|
13
|
+
throw AppError.unauthorized('Invalid email or password', 'INVALID_CREDENTIALS');
|
|
14
|
+
}
|
|
15
|
+
const tokenPayload = { userId: String(user._id), email: user.email };
|
|
16
|
+
const accessToken = generateAccessToken(tokenPayload, jwtConfig);
|
|
17
|
+
const refreshToken = generateRefreshToken(tokenPayload, jwtConfig);
|
|
18
|
+
return { user: sanitizeUser(user), tokens: { accessToken, refreshToken } };
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=login.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.service.js","sourceRoot":"","sources":["../../../src/features/login/login.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE3D,MAAM,CAAC,MAAM,SAAS,GAAG,KAAK,EAC1B,KAAiB,EACjB,MAAwB,EACJ,EAAE;IACtB,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC;IAE7C,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IACjF,IAAI,CAAC,IAAI,EAAE,CAAC;QACR,MAAM,QAAQ,CAAC,YAAY,CAAC,2BAA2B,EAAE,qBAAqB,CAAC,CAAC;IACpF,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IACrE,IAAI,CAAC,OAAO,EAAE,CAAC;QACX,MAAM,QAAQ,CAAC,YAAY,CAAC,2BAA2B,EAAE,qBAAqB,CAAC,CAAC;IACpF,CAAC;IAED,MAAM,YAAY,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;IACrE,MAAM,WAAW,GAAG,mBAAmB,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;IACjE,MAAM,YAAY,GAAG,oBAAoB,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;IAEnE,OAAO,EAAE,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,YAAY,EAAE,EAAE,CAAC;AAC/E,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.validator.d.ts","sourceRoot":"","sources":["../../../src/features/login/login.validator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAGvD,eAAO,MAAM,kBAAkB,GAAI,MAAM,OAAO,KAAG,UAgBlD,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { AppError } from '../../utils/AppError.js';
|
|
2
|
+
export const validateLoginInput = (body) => {
|
|
3
|
+
if (typeof body !== 'object' || body === null) {
|
|
4
|
+
throw AppError.badRequest('Request body is required', 'INVALID_BODY');
|
|
5
|
+
}
|
|
6
|
+
const { email, password } = body;
|
|
7
|
+
if (typeof email !== 'string' || !email.trim()) {
|
|
8
|
+
throw AppError.badRequest('Email is required', 'EMAIL_REQUIRED');
|
|
9
|
+
}
|
|
10
|
+
if (typeof password !== 'string' || !password) {
|
|
11
|
+
throw AppError.badRequest('Password is required', 'PASSWORD_REQUIRED');
|
|
12
|
+
}
|
|
13
|
+
return { email: email.toLowerCase().trim(), password };
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=login.validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.validator.js","sourceRoot":"","sources":["../../../src/features/login/login.validator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAEnD,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,IAAa,EAAc,EAAE;IAC5D,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAC5C,MAAM,QAAQ,CAAC,UAAU,CAAC,0BAA0B,EAAE,cAAc,CAAC,CAAC;IAC1E,CAAC;IAED,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,IAA+B,CAAC;IAE5D,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;QAC7C,MAAM,QAAQ,CAAC,UAAU,CAAC,mBAAmB,EAAE,gBAAgB,CAAC,CAAC;IACrE,CAAC;IAED,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC5C,MAAM,QAAQ,CAAC,UAAU,CAAC,sBAAsB,EAAE,mBAAmB,CAAC,CAAC;IAC3E,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,CAAC;AAC3D,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"me.controller.d.ts","sourceRoot":"","sources":["../../../src/features/me/me.controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAM1D,eAAO,MAAM,YAAY,GACrB,KAAK,OAAO,EACZ,KAAK,QAAQ,EACb,MAAM,YAAY,KACnB,OAAO,CAAC,IAAI,CAiBd,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { getConfig } from '../../core/stores/config.store.js';
|
|
2
|
+
import { AppError } from '../../utils/AppError.js';
|
|
3
|
+
import { sendSuccess } from '../../utils/response.js';
|
|
4
|
+
import { sanitizeUser } from '../../utils/sanitizeUser.js';
|
|
5
|
+
export const meController = async (req, res, next) => {
|
|
6
|
+
try {
|
|
7
|
+
if (!req.user) {
|
|
8
|
+
throw AppError.unauthorized('Authentication required');
|
|
9
|
+
}
|
|
10
|
+
const { userModel } = getConfig();
|
|
11
|
+
const user = await userModel.findById(req.user.id);
|
|
12
|
+
if (!user) {
|
|
13
|
+
throw AppError.notFound('User not found', 'USER_NOT_FOUND');
|
|
14
|
+
}
|
|
15
|
+
sendSuccess(res, sanitizeUser(user));
|
|
16
|
+
}
|
|
17
|
+
catch (err) {
|
|
18
|
+
next(err);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=me.controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"me.controller.js","sourceRoot":"","sources":["../../../src/features/me/me.controller.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE3D,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,EAC7B,GAAY,EACZ,GAAa,EACb,IAAkB,EACL,EAAE;IACf,IAAI,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;YACZ,MAAM,QAAQ,CAAC,YAAY,CAAC,yBAAyB,CAAC,CAAC;QAC3D,CAAC;QAED,MAAM,EAAE,SAAS,EAAE,GAAG,SAAS,EAAE,CAAC;QAElC,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACnD,IAAI,CAAC,IAAI,EAAE,CAAC;YACR,MAAM,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,CAAC;QAChE,CAAC;QAED,WAAW,CAAC,GAAG,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;IACzC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,IAAI,CAAC,GAAG,CAAC,CAAC;IACd,CAAC;AACL,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register.controller.d.ts","sourceRoot":"","sources":["../../../src/features/register/register.controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAM1D,eAAO,MAAM,kBAAkB,GAC3B,KAAK,OAAO,EACZ,KAAK,QAAQ,EACb,MAAM,YAAY,KACnB,OAAO,CAAC,IAAI,CAUd,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { getConfig } from '../../core/stores/config.store.js';
|
|
2
|
+
import { sendSuccess } from '../../utils/response.js';
|
|
3
|
+
import { registerUser } from './register.service.js';
|
|
4
|
+
import { validateRegisterInput } from './register.validator.js';
|
|
5
|
+
export const registerController = async (req, res, next) => {
|
|
6
|
+
try {
|
|
7
|
+
const input = validateRegisterInput(req.body);
|
|
8
|
+
const config = getConfig();
|
|
9
|
+
const result = await registerUser(input, config);
|
|
10
|
+
sendSuccess(res, result, 'Registration successful', 201);
|
|
11
|
+
}
|
|
12
|
+
catch (err) {
|
|
13
|
+
next(err);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=register.controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register.controller.js","sourceRoot":"","sources":["../../../src/features/register/register.controller.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,EACnC,GAAY,EACZ,GAAa,EACb,IAAkB,EACL,EAAE;IACf,IAAI,CAAC;QACD,MAAM,KAAK,GAAG,qBAAqB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC9C,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAEjD,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,yBAAyB,EAAE,GAAG,CAAC,CAAC;IAC7D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,IAAI,CAAC,GAAG,CAAC,CAAC;IACd,CAAC;AACL,CAAC,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { RegisterInput, RegisterResult } from '../../types/auth.types.js';
|
|
2
|
+
import { SecureAuthConfig } from '../../types/config.types.js';
|
|
3
|
+
export declare const registerUser: (input: RegisterInput, config: SecureAuthConfig) => Promise<RegisterResult>;
|
|
4
|
+
//# sourceMappingURL=register.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register.service.d.ts","sourceRoot":"","sources":["../../../src/features/register/register.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAM/D,eAAO,MAAM,YAAY,GACrB,OAAO,aAAa,EACpB,QAAQ,gBAAgB,KACzB,OAAO,CAAC,cAAc,CAuBxB,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { AppError } from '../../utils/AppError.js';
|
|
2
|
+
import { hashPassword } from '../../utils/hash.js';
|
|
3
|
+
import { generateAccessToken, generateRefreshToken } from '../../utils/jwt.js';
|
|
4
|
+
import { sanitizeUser } from '../../utils/sanitizeUser.js';
|
|
5
|
+
export const registerUser = async (input, config) => {
|
|
6
|
+
const { userModel, jwt: jwtConfig } = config;
|
|
7
|
+
const existingUser = await userModel.findOne({ email: input.email });
|
|
8
|
+
if (existingUser) {
|
|
9
|
+
throw AppError.badRequest('Email is already registered', 'EMAIL_TAKEN');
|
|
10
|
+
}
|
|
11
|
+
const hash_password = await hashPassword(input.password);
|
|
12
|
+
const user = await userModel.create({
|
|
13
|
+
...input,
|
|
14
|
+
password: hash_password,
|
|
15
|
+
});
|
|
16
|
+
const tokenPayload = { userId: String(user._id), email: user.email };
|
|
17
|
+
const accessToken = generateAccessToken(tokenPayload, jwtConfig);
|
|
18
|
+
const refreshToken = generateRefreshToken(tokenPayload, jwtConfig);
|
|
19
|
+
return {
|
|
20
|
+
user: sanitizeUser(user),
|
|
21
|
+
tokens: { accessToken, refreshToken },
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=register.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register.service.js","sourceRoot":"","sources":["../../../src/features/register/register.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE3D,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,EAC7B,KAAoB,EACpB,MAAwB,EACD,EAAE;IACzB,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC;IAE7C,MAAM,YAAY,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;IACrE,IAAI,YAAY,EAAE,CAAC;QACf,MAAM,QAAQ,CAAC,UAAU,CAAC,6BAA6B,EAAE,aAAa,CAAC,CAAC;IAC5E,CAAC;IAED,MAAM,aAAa,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAEzD,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC;QAChC,GAAG,KAAK;QACR,QAAQ,EAAE,aAAa;KAC1B,CAAC,CAAC;IAEH,MAAM,YAAY,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;IACrE,MAAM,WAAW,GAAG,mBAAmB,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;IACjE,MAAM,YAAY,GAAG,oBAAoB,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;IAEnE,OAAO;QACH,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC;QACxB,MAAM,EAAE,EAAE,WAAW,EAAE,YAAY,EAAE;KACxC,CAAC;AACN,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register.validator.d.ts","sourceRoot":"","sources":["../../../src/features/register/register.validator.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAG1D,eAAO,MAAM,qBAAqB,GAAI,MAAM,OAAO,KAAG,aAuDrD,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { EMAIL_REGEX, MIN_PASSWORD_LENGTH, PASSWORD_LOWERCASE_REGEX, PASSWORD_NUMBER_REGEX, PASSWORD_SPECIAL_CHARACTER_REGEX, PASSWORD_UPPERCASE_REGEX, } from '../../constants/index.js';
|
|
2
|
+
import { AppError } from '../../utils/AppError.js';
|
|
3
|
+
export const validateRegisterInput = (body) => {
|
|
4
|
+
if (typeof body !== 'object' || body === null) {
|
|
5
|
+
throw AppError.badRequest('Request body is required', 'INVALID_BODY');
|
|
6
|
+
}
|
|
7
|
+
const { email, password, ...rest } = body;
|
|
8
|
+
if (typeof email !== 'string' || !email.trim()) {
|
|
9
|
+
throw AppError.badRequest('Email is required', 'EMAIL_REQUIRED');
|
|
10
|
+
}
|
|
11
|
+
if (!EMAIL_REGEX.test(email)) {
|
|
12
|
+
throw AppError.badRequest('Invalid email format', 'EMAIL_INVALID');
|
|
13
|
+
}
|
|
14
|
+
if (typeof password !== 'string' || !password) {
|
|
15
|
+
throw AppError.badRequest('Password is required', 'PASSWORD_REQUIRED');
|
|
16
|
+
}
|
|
17
|
+
if (password.length < MIN_PASSWORD_LENGTH) {
|
|
18
|
+
throw AppError.badRequest(`Password must be at least ${MIN_PASSWORD_LENGTH} characters`, 'PASSWORD_TOO_SHORT');
|
|
19
|
+
}
|
|
20
|
+
if (!PASSWORD_UPPERCASE_REGEX.test(password)) {
|
|
21
|
+
throw AppError.badRequest('Password must be at least one uppercase letter', 'PASSWORD_MISSING_UPPERCASE_LETTER');
|
|
22
|
+
}
|
|
23
|
+
if (!PASSWORD_LOWERCASE_REGEX.test(password)) {
|
|
24
|
+
throw AppError.badRequest('Password must be at least one lowercase letter', 'PASSWORD_MISSING_LOWERCASE_LETTER');
|
|
25
|
+
}
|
|
26
|
+
if (!PASSWORD_NUMBER_REGEX.test(password)) {
|
|
27
|
+
throw AppError.badRequest('Password must contain at least one number', 'PASSWORD_MISSING_NUMBER');
|
|
28
|
+
}
|
|
29
|
+
if (!PASSWORD_SPECIAL_CHARACTER_REGEX.test(password)) {
|
|
30
|
+
throw AppError.badRequest('Password must be at least one special character', 'PASSWORD_MISSING_SPECIAL_CHARACTER');
|
|
31
|
+
}
|
|
32
|
+
return { email: email.toLowerCase().trim(), password, ...rest };
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=register.validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register.validator.js","sourceRoot":"","sources":["../../../src/features/register/register.validator.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,WAAW,EACX,mBAAmB,EACnB,wBAAwB,EACxB,qBAAqB,EACrB,gCAAgC,EAChC,wBAAwB,GAC3B,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAEnD,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,IAAa,EAAiB,EAAE;IAClE,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAC5C,MAAM,QAAQ,CAAC,UAAU,CAAC,0BAA0B,EAAE,cAAc,CAAC,CAAC;IAC1E,CAAC;IAED,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,IAA+B,CAAC;IAErE,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;QAC7C,MAAM,QAAQ,CAAC,UAAU,CAAC,mBAAmB,EAAE,gBAAgB,CAAC,CAAC;IACrE,CAAC;IAED,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3B,MAAM,QAAQ,CAAC,UAAU,CAAC,sBAAsB,EAAE,eAAe,CAAC,CAAC;IACvE,CAAC;IAED,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC5C,MAAM,QAAQ,CAAC,UAAU,CAAC,sBAAsB,EAAE,mBAAmB,CAAC,CAAC;IAC3E,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,GAAG,mBAAmB,EAAE,CAAC;QACxC,MAAM,QAAQ,CAAC,UAAU,CACrB,6BAA6B,mBAAmB,aAAa,EAC7D,oBAAoB,CACvB,CAAC;IACN,CAAC;IAED,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC3C,MAAM,QAAQ,CAAC,UAAU,CACrB,gDAAgD,EAChD,mCAAmC,CACtC,CAAC;IACN,CAAC;IAED,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC3C,MAAM,QAAQ,CAAC,UAAU,CACrB,gDAAgD,EAChD,mCAAmC,CACtC,CAAC;IACN,CAAC;IAED,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxC,MAAM,QAAQ,CAAC,UAAU,CACrB,2CAA2C,EAC3C,yBAAyB,CAC5B,CAAC;IACN,CAAC;IAED,IAAI,CAAC,gCAAgC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QACnD,MAAM,QAAQ,CAAC,UAAU,CACrB,iDAAiD,EACjD,oCAAoC,CACvC,CAAC;IACN,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,CAAC;AACpE,CAAC,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAIlC,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAWvE"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { errorMiddleware } from './core/middleware/error.middleware.js';
|
|
2
|
+
import { createAuthRouter } from './core/routes/auth.routes.js';
|
|
3
|
+
import { setConfig } from './core/stores/config.store.js';
|
|
4
|
+
export function secureAuth(app, config) {
|
|
5
|
+
validateConfig(config);
|
|
6
|
+
setConfig(config);
|
|
7
|
+
const prefix = config.routePrefix ?? '/auth';
|
|
8
|
+
// Core auth router
|
|
9
|
+
app.use(prefix, createAuthRouter());
|
|
10
|
+
// Error Handler
|
|
11
|
+
app.use(errorMiddleware);
|
|
12
|
+
}
|
|
13
|
+
const validateConfig = (config) => {
|
|
14
|
+
if (!config.userModel) {
|
|
15
|
+
throw new Error('[secure-auth-kit] config.userModel is required. ' +
|
|
16
|
+
'Pass your Mongoose User model: secureAuth(app, {userModel: User, ... })');
|
|
17
|
+
}
|
|
18
|
+
if (!config.jwt?.secret) {
|
|
19
|
+
throw new Error('[secure-auth-kit] config.jwt.secret is required. ' +
|
|
20
|
+
'Set JWT_SECRET in your environment and pass it via: jwt: { secret: process.env.JWT_SECRET }');
|
|
21
|
+
}
|
|
22
|
+
const emailPath = config.userModel.schema.path('email');
|
|
23
|
+
if (!emailPath) {
|
|
24
|
+
throw new Error('[secure-auth-kit] Your User model is missing the required "email" field.' +
|
|
25
|
+
'Add `email: { type: String, required: true, unique: true }` to your schema.');
|
|
26
|
+
}
|
|
27
|
+
const passwordPath = config.userModel.schema.path('password');
|
|
28
|
+
if (!passwordPath) {
|
|
29
|
+
throw new Error('[secure-auth-kit] Your User model is missing the required "password" field.' +
|
|
30
|
+
'Add `password: { type: String, required: true}` to your schema.');
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAG1D,MAAM,UAAU,UAAU,CAAC,GAAY,EAAE,MAAwB;IAC7D,cAAc,CAAC,MAAM,CAAC,CAAC;IAEvB,SAAS,CAAC,MAAM,CAAC,CAAC;IAElB,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,IAAI,OAAO,CAAC;IAC7C,mBAAmB;IACnB,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAC;IAEpC,gBAAgB;IAChB,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,cAAc,GAAG,CAAC,MAAwB,EAAQ,EAAE;IACtD,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CACX,kDAAkD;YAC9C,yEAAyE,CAChF,CAAC;IACN,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CACX,mDAAmD;YAC/C,6FAA6F,CACpG,CAAC;IACN,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACxD,IAAI,CAAC,SAAS,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACX,0EAA0E;YACtE,6EAA6E,CACpF,CAAC;IACN,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC9D,IAAI,CAAC,YAAY,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CACX,6EAA6E;YACzE,iEAAiE,CACxE,CAAC;IACN,CAAC;AACL,CAAC,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { NextFunction, Request, Response } from 'express';
|
|
2
|
+
export declare const extractBearerToken: (authHeader: string | undefined) => string | null;
|
|
3
|
+
export declare const authenticate: (req: Request, res: Response, next: NextFunction) => void;
|
|
4
|
+
//# sourceMappingURL=authenticate.middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authenticate.middleware.d.ts","sourceRoot":"","sources":["../../src/middleware/authenticate.middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAK1D,eAAO,MAAM,kBAAkB,GAAI,YAAY,MAAM,GAAG,SAAS,KAAG,MAAM,GAAG,IAI5E,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,KAAG,IAqB9E,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { getConfig } from '../core/stores/config.store.js';
|
|
2
|
+
import { AppError } from '../utils/AppError.js';
|
|
3
|
+
import { verifyToken } from '../utils/jwt.js';
|
|
4
|
+
export const extractBearerToken = (authHeader) => {
|
|
5
|
+
if (!authHeader?.startsWith('Bearer '))
|
|
6
|
+
return null;
|
|
7
|
+
const token = authHeader.slice(7).trim();
|
|
8
|
+
return token || null;
|
|
9
|
+
};
|
|
10
|
+
export const authenticate = (req, res, next) => {
|
|
11
|
+
try {
|
|
12
|
+
const token = extractBearerToken(req.headers.authorization);
|
|
13
|
+
if (!token) {
|
|
14
|
+
throw AppError.unauthorized('Bearer token is required', 'TOKEN_MISSING');
|
|
15
|
+
}
|
|
16
|
+
const config = getConfig();
|
|
17
|
+
const payload = verifyToken(token, config.jwt);
|
|
18
|
+
if (payload.type === 'access') {
|
|
19
|
+
throw AppError.unauthorized('Invalid token type', 'TOKEN_TYPE_MISMATCH');
|
|
20
|
+
}
|
|
21
|
+
req.user = { id: payload.userId, email: payload.email };
|
|
22
|
+
next();
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
next(err);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=authenticate.middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authenticate.middleware.js","sourceRoot":"","sources":["../../src/middleware/authenticate.middleware.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE9C,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,UAA8B,EAAiB,EAAE;IAChF,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,IAAI,CAAC;IACpD,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACzC,OAAO,KAAK,IAAI,IAAI,CAAC;AACzB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAQ,EAAE;IAClF,IAAI,CAAC;QACD,MAAM,KAAK,GAAG,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QAE5D,IAAI,CAAC,KAAK,EAAE,CAAC;YACT,MAAM,QAAQ,CAAC,YAAY,CAAC,0BAA0B,EAAE,eAAe,CAAC,CAAC;QAC7E,CAAC;QAED,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;QAE/C,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC5B,MAAM,QAAQ,CAAC,YAAY,CAAC,oBAAoB,EAAE,qBAAqB,CAAC,CAAC;QAC7E,CAAC;QAED,GAAG,CAAC,IAAI,GAAG,EAAE,EAAE,EAAE,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;QAExD,IAAI,EAAE,CAAC;IACX,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,IAAI,CAAC,GAAG,CAAC,CAAC;IACd,CAAC;AACL,CAAC,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export interface AuthenticatedUser {
|
|
2
|
+
id: string;
|
|
3
|
+
email: string;
|
|
4
|
+
[key: string]: unknown;
|
|
5
|
+
}
|
|
6
|
+
export interface RegisterInput {
|
|
7
|
+
email: string;
|
|
8
|
+
password: string;
|
|
9
|
+
[key: string]: unknown;
|
|
10
|
+
}
|
|
11
|
+
export interface LoginInput {
|
|
12
|
+
email: string;
|
|
13
|
+
password: string;
|
|
14
|
+
}
|
|
15
|
+
export interface SanitizedUser {
|
|
16
|
+
id: string;
|
|
17
|
+
email: string;
|
|
18
|
+
[key: string]: unknown;
|
|
19
|
+
}
|
|
20
|
+
export interface AuthTokens {
|
|
21
|
+
accessToken: string;
|
|
22
|
+
refreshToken: string;
|
|
23
|
+
}
|
|
24
|
+
export interface RegisterResult {
|
|
25
|
+
user: SanitizedUser;
|
|
26
|
+
tokens: AuthTokens;
|
|
27
|
+
}
|
|
28
|
+
export interface LoginResult {
|
|
29
|
+
user: SanitizedUser;
|
|
30
|
+
tokens: AuthTokens;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=auth.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.types.d.ts","sourceRoot":"","sources":["../../src/types/auth.types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,UAAU;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,UAAU;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC3B,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,UAAU,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,UAAU,CAAC;CACtB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.types.js","sourceRoot":"","sources":["../../src/types/auth.types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Document, Model } from 'mongoose';
|
|
2
|
+
import { JWTConfig } from './jwt.types.js';
|
|
3
|
+
export interface UserDocument extends Document {
|
|
4
|
+
email: string;
|
|
5
|
+
password: string;
|
|
6
|
+
[key: string]: unknown;
|
|
7
|
+
}
|
|
8
|
+
export interface SecureAuthConfig {
|
|
9
|
+
userModel: Model<UserDocument>;
|
|
10
|
+
jwt: JWTConfig;
|
|
11
|
+
routePrefix?: string;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=config.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.types.d.ts","sourceRoot":"","sources":["../../src/types/config.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,MAAM,WAAW,YAAa,SAAQ,QAAQ;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC7B,SAAS,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;IAC/B,GAAG,EAAE,SAAS,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.types.js","sourceRoot":"","sources":["../../src/types/config.types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface TokenPayload {
|
|
2
|
+
userId: string;
|
|
3
|
+
email: string;
|
|
4
|
+
type: 'access' | 'refresh';
|
|
5
|
+
exp?: number;
|
|
6
|
+
}
|
|
7
|
+
export interface JWTConfig {
|
|
8
|
+
secret: string;
|
|
9
|
+
accessTokenExpiry?: string;
|
|
10
|
+
refreshTokenExpiry?: string;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=jwt.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwt.types.d.ts","sourceRoot":"","sources":["../../src/types/jwt.types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,SAAS;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC/B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwt.types.js","sourceRoot":"","sources":["../../src/types/jwt.types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare class AppError extends Error {
|
|
2
|
+
readonly statusCode: number;
|
|
3
|
+
readonly isOperational: boolean;
|
|
4
|
+
readonly code?: string;
|
|
5
|
+
constructor(message: string, statusCode: number, code?: string);
|
|
6
|
+
static badRequest(message: string, code?: string): AppError;
|
|
7
|
+
static unauthorized(message?: string, code?: string): AppError;
|
|
8
|
+
static forbidden(message?: string, code?: string): AppError;
|
|
9
|
+
static notFound(message?: string, code?: string): AppError;
|
|
10
|
+
static internal(message?: string, code?: string): AppError;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=AppError.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AppError.d.ts","sourceRoot":"","sources":["../../src/utils/AppError.ts"],"names":[],"mappings":"AAAA,qBAAa,QAAS,SAAQ,KAAK;IAC/B,SAAgB,UAAU,EAAE,MAAM,CAAC;IACnC,SAAgB,aAAa,EAAE,OAAO,CAAC;IACvC,SAAgB,IAAI,CAAC,EAAE,MAAM,CAAC;gBAElB,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM;IAW9D,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,QAAQ;IAI3D,MAAM,CAAC,YAAY,CAAC,OAAO,SAAiB,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,QAAQ;IAItE,MAAM,CAAC,SAAS,CAAC,OAAO,SAAc,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,QAAQ;IAIhE,MAAM,CAAC,QAAQ,CAAC,OAAO,SAAc,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,QAAQ;IAI/D,MAAM,CAAC,QAAQ,CAAC,OAAO,SAA0B,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,QAAQ;CAG9E"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export class AppError extends Error {
|
|
2
|
+
statusCode;
|
|
3
|
+
isOperational;
|
|
4
|
+
code;
|
|
5
|
+
constructor(message, statusCode, code) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.statusCode = statusCode;
|
|
8
|
+
this.isOperational = true;
|
|
9
|
+
this.code = code;
|
|
10
|
+
// Restore prototype chain
|
|
11
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
12
|
+
Error.captureStackTrace(this, this.constructor);
|
|
13
|
+
}
|
|
14
|
+
static badRequest(message, code) {
|
|
15
|
+
return new AppError(message, 400, code);
|
|
16
|
+
}
|
|
17
|
+
static unauthorized(message = 'Unauthorized', code) {
|
|
18
|
+
return new AppError(message, 401, code);
|
|
19
|
+
}
|
|
20
|
+
static forbidden(message = 'Forbidden', code) {
|
|
21
|
+
return new AppError(message, 403, code);
|
|
22
|
+
}
|
|
23
|
+
static notFound(message = 'Not found', code) {
|
|
24
|
+
return new AppError(message, 404, code);
|
|
25
|
+
}
|
|
26
|
+
static internal(message = 'Internal server error', code) {
|
|
27
|
+
return new AppError(message, 500, code);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=AppError.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AppError.js","sourceRoot":"","sources":["../../src/utils/AppError.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,QAAS,SAAQ,KAAK;IACf,UAAU,CAAS;IACnB,aAAa,CAAU;IACvB,IAAI,CAAU;IAE9B,YAAY,OAAe,EAAE,UAAkB,EAAE,IAAa;QAC1D,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAC1B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QAEjB,0BAA0B;QAC1B,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,CAAC,UAAU,CAAC,OAAe,EAAE,IAAa;QAC5C,OAAO,IAAI,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;IAC5C,CAAC;IAED,MAAM,CAAC,YAAY,CAAC,OAAO,GAAG,cAAc,EAAE,IAAa;QACvD,OAAO,IAAI,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;IAC5C,CAAC;IAED,MAAM,CAAC,SAAS,CAAC,OAAO,GAAG,WAAW,EAAE,IAAa;QACjD,OAAO,IAAI,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;IAC5C,CAAC;IAED,MAAM,CAAC,QAAQ,CAAC,OAAO,GAAG,WAAW,EAAE,IAAa;QAChD,OAAO,IAAI,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;IAC5C,CAAC;IAED,MAAM,CAAC,QAAQ,CAAC,OAAO,GAAG,uBAAuB,EAAE,IAAa;QAC5D,OAAO,IAAI,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;IAC5C,CAAC;CACJ"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../src/utils/hash.ts"],"names":[],"mappings":"AAGA,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAErE;AAED,wBAAsB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAEzF"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import bcrypt from 'bcryptjs';
|
|
2
|
+
import { SALT_ROUNDS } from '../constants/index.js';
|
|
3
|
+
export async function hashPassword(plaintext) {
|
|
4
|
+
return bcrypt.hash(plaintext, SALT_ROUNDS);
|
|
5
|
+
}
|
|
6
|
+
export async function comparePassword(plaintext, hashed) {
|
|
7
|
+
return bcrypt.compare(plaintext, hashed);
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=hash.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash.js","sourceRoot":"","sources":["../../src/utils/hash.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,SAAiB;IAChD,OAAO,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,SAAiB,EAAE,MAAc;IACnE,OAAO,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { JWTConfig, TokenPayload } from '../types/jwt.types.js';
|
|
2
|
+
export declare function generateAccessToken(payload: Omit<TokenPayload, 'type' | 'exp'>, config: JWTConfig): string;
|
|
3
|
+
export declare function generateRefreshToken(payload: Omit<TokenPayload, 'type' | 'exp'>, config: JWTConfig): string;
|
|
4
|
+
export declare function verifyToken(token: string, config: JWTConfig): TokenPayload;
|
|
5
|
+
//# sourceMappingURL=jwt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../src/utils/jwt.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAGhE,wBAAgB,mBAAmB,CAC/B,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,KAAK,CAAC,EAC3C,MAAM,EAAE,SAAS,GAClB,MAAM,CAIR;AAED,wBAAgB,oBAAoB,CAChC,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,KAAK,CAAC,EAC3C,MAAM,EAAE,SAAS,GAClB,MAAM,CAIR;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,YAAY,CAc1E"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import jwt from 'jsonwebtoken';
|
|
2
|
+
import { AppError } from './AppError.js';
|
|
3
|
+
export function generateAccessToken(payload, config) {
|
|
4
|
+
return jwt.sign({ ...payload, type: 'access' }, config.secret, {
|
|
5
|
+
expiresIn: config.accessTokenExpiry ?? '15m',
|
|
6
|
+
});
|
|
7
|
+
}
|
|
8
|
+
export function generateRefreshToken(payload, config) {
|
|
9
|
+
return jwt.sign({ ...payload, type: 'refresh' }, config.secret, {
|
|
10
|
+
expiresIn: config.refreshTokenExpiry ?? '7d',
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
export function verifyToken(token, config) {
|
|
14
|
+
try {
|
|
15
|
+
return jwt.verify(token, config.secret);
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
if (error instanceof jwt.TokenExpiredError) {
|
|
19
|
+
throw AppError.unauthorized('Token has expired', 'TOKEN_EXPIRED');
|
|
20
|
+
}
|
|
21
|
+
if (error instanceof jwt.JsonWebTokenError) {
|
|
22
|
+
throw AppError.unauthorized('Invalid token', 'TOKEN_INVALID');
|
|
23
|
+
}
|
|
24
|
+
throw AppError.unauthorized('Token verification failed');
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=jwt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwt.js","sourceRoot":"","sources":["../../src/utils/jwt.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,cAAc,CAAC;AAE/B,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,MAAM,UAAU,mBAAmB,CAC/B,OAA2C,EAC3C,MAAiB;IAEjB,OAAO,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE;QAC3D,SAAS,EAAE,MAAM,CAAC,iBAAiB,IAAI,KAAK;KAC5B,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,oBAAoB,CAChC,OAA2C,EAC3C,MAAiB;IAEjB,OAAO,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE;QAC5D,SAAS,EAAE,MAAM,CAAC,kBAAkB,IAAI,IAAI;KAC5B,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAa,EAAE,MAAiB;IACxD,IAAI,CAAC;QACD,OAAO,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAiB,CAAC;IAC5D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,IAAI,KAAK,YAAY,GAAG,CAAC,iBAAiB,EAAE,CAAC;YACzC,MAAM,QAAQ,CAAC,YAAY,CAAC,mBAAmB,EAAE,eAAe,CAAC,CAAC;QACtE,CAAC;QAED,IAAI,KAAK,YAAY,GAAG,CAAC,iBAAiB,EAAE,CAAC;YACzC,MAAM,QAAQ,CAAC,YAAY,CAAC,eAAe,EAAE,eAAe,CAAC,CAAC;QAClE,CAAC;QAED,MAAM,QAAQ,CAAC,YAAY,CAAC,2BAA2B,CAAC,CAAC;IAC7D,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Response } from 'express';
|
|
2
|
+
export interface SuccessResponse<T = unknown> {
|
|
3
|
+
success: true;
|
|
4
|
+
data: T;
|
|
5
|
+
message?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface ErrorResponse {
|
|
8
|
+
success: false;
|
|
9
|
+
error: {
|
|
10
|
+
message: string;
|
|
11
|
+
code?: string;
|
|
12
|
+
statusCode: number;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export declare function sendSuccess<T>(res: Response, data: T, message?: string, statusCode?: number): void;
|
|
16
|
+
export declare function sendError(res: Response, message: string, statusCode?: number, code?: string): void;
|
|
17
|
+
//# sourceMappingURL=response.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response.d.ts","sourceRoot":"","sources":["../../src/utils/response.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,MAAM,WAAW,eAAe,CAAC,CAAC,GAAG,OAAO;IACxC,OAAO,EAAE,IAAI,CAAC;IACd,IAAI,EAAE,CAAC,CAAC;IACR,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC1B,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,EAAE;QACH,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,CAAC;KACtB,CAAC;CACL;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,UAAU,SAAM,GAAG,IAAI,CAO/F;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,SAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAU/F"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export function sendSuccess(res, data, message, statusCode = 200) {
|
|
2
|
+
const body = {
|
|
3
|
+
success: true,
|
|
4
|
+
data,
|
|
5
|
+
...(message ? { message } : {}),
|
|
6
|
+
};
|
|
7
|
+
res.status(statusCode).json(body);
|
|
8
|
+
}
|
|
9
|
+
export function sendError(res, message, statusCode = 500, code) {
|
|
10
|
+
const body = {
|
|
11
|
+
success: false,
|
|
12
|
+
error: {
|
|
13
|
+
message,
|
|
14
|
+
statusCode,
|
|
15
|
+
...(code ? { code } : {}),
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
res.status(statusCode).json(body);
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=response.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response.js","sourceRoot":"","sources":["../../src/utils/response.ts"],"names":[],"mappings":"AAiBA,MAAM,UAAU,WAAW,CAAI,GAAa,EAAE,IAAO,EAAE,OAAgB,EAAE,UAAU,GAAG,GAAG;IACrF,MAAM,IAAI,GAAuB;QAC7B,OAAO,EAAE,IAAI;QACb,IAAI;QACJ,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAClC,CAAC;IACF,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,GAAa,EAAE,OAAe,EAAE,UAAU,GAAG,GAAG,EAAE,IAAa;IACrF,MAAM,IAAI,GAAkB;QACxB,OAAO,EAAE,KAAK;QACd,KAAK,EAAE;YACH,OAAO;YACP,UAAU;YACV,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC5B;KACJ,CAAC;IACF,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACtC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitizeUser.d.ts","sourceRoot":"","sources":["../../src/utils/sanitizeUser.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAExD,wBAAgB,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,aAAa,CAkB9D"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { SENSITIVE_FIELDS } from '../constants/index.js';
|
|
2
|
+
export function sanitizeUser(user) {
|
|
3
|
+
const raw = typeof user.toObject === 'function' ? user.toObject() : { ...user };
|
|
4
|
+
const sanitized = {};
|
|
5
|
+
for (const [key, val] of Object.entries(raw)) {
|
|
6
|
+
if (!SENSITIVE_FIELDS.has(key)) {
|
|
7
|
+
sanitized[key] = val;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
// Normalize _id -> id
|
|
11
|
+
if (raw._id !== undefined) {
|
|
12
|
+
sanitized['id'] = String(raw._id);
|
|
13
|
+
delete sanitized['_id'];
|
|
14
|
+
}
|
|
15
|
+
return sanitized;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=sanitizeUser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitizeUser.js","sourceRoot":"","sources":["../../src/utils/sanitizeUser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAIzD,MAAM,UAAU,YAAY,CAAC,IAAkB;IAC3C,MAAM,GAAG,GAAG,OAAO,IAAI,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC;IAEhF,MAAM,SAAS,GAA4B,EAAE,CAAC;IAE9C,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3C,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAC7B,SAAS,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;QACzB,CAAC;IACL,CAAC;IAED,sBAAsB;IACtB,IAAI,GAAG,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;QACxB,SAAS,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IAED,OAAO,SAA0B,CAAC;AACtC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "secure-auth-kit",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Authentication toolkit for Express and MongoDB",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=18"
|
|
19
|
+
},
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsc"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"authentication",
|
|
25
|
+
"jwt",
|
|
26
|
+
"express",
|
|
27
|
+
"mongoose",
|
|
28
|
+
"typescript",
|
|
29
|
+
"auth"
|
|
30
|
+
],
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"express": "^5.0.0",
|
|
34
|
+
"mongoose": "^8.0.0"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"bcryptjs": "^2.4.3",
|
|
38
|
+
"jsonwebtoken": "^9.0.2"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/bcryptjs": "^2.4.6",
|
|
42
|
+
"@types/express": "^5.0.0",
|
|
43
|
+
"@types/jsonwebtoken": "^9.0.6",
|
|
44
|
+
"@types/node": "^20.0.0",
|
|
45
|
+
"typescript": "^5.4.0",
|
|
46
|
+
"express": "^5.2.1",
|
|
47
|
+
"mongoose": "^8.24.0"
|
|
48
|
+
}
|
|
49
|
+
}
|