@medi-car-bd/mcb-shared-auth 0.0.13 → 0.0.15
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/LICENSE +21 -21
- package/README.md +277 -19
- package/package.json +77 -64
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2024 FatihOnlinEShopBD
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 FatihOnlinEShopBD
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,44 +1,302 @@
|
|
|
1
|
-
# mcb-
|
|
1
|
+
# @medi-car-bd/mcb-shared-auth
|
|
2
|
+
|
|
3
|
+
Shared authentication library for the Medi Car BD microservices platform.
|
|
4
|
+
|
|
5
|
+
One implementation of JWT issuance, refresh-token rotation and role-based
|
|
6
|
+
authorization, used by every backend service. When a service and the API
|
|
7
|
+
gateway disagree about what a valid token is, the disagreement becomes an
|
|
8
|
+
authentication bug — this package exists to make that impossible.
|
|
9
|
+
|
|
10
|
+
**It is a library, not a service.** It has no database, no HTTP server and no
|
|
11
|
+
ORM. You inject the persistence it needs through an interface, which is what
|
|
12
|
+
lets the auth service own a database while every other service owns none.
|
|
13
|
+
|
|
14
|
+
Currently at **v0.0.8**. Used in production across `mcb-auth-service`,
|
|
15
|
+
`mcb-api-gateway`, `mcb-hrm-client`, `mcb-org-client`, `mcb-billing-client` and
|
|
16
|
+
`mcb-dashboard-client`.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
2
19
|
|
|
3
20
|
```bash
|
|
4
|
-
|
|
21
|
+
pnpm add @medi-car-bd/mcb-shared-auth
|
|
22
|
+
# or
|
|
23
|
+
npm install @medi-car-bd/mcb-shared-auth
|
|
5
24
|
```
|
|
6
25
|
|
|
7
|
-
|
|
26
|
+
Requires **Express 4** as a peer dependency (`^4.18.2`). The package targets
|
|
27
|
+
CommonJS and ships type declarations.
|
|
8
28
|
|
|
9
|
-
|
|
10
|
-
|
|
29
|
+
## Quick start
|
|
30
|
+
|
|
31
|
+
### Protect a route
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import {
|
|
35
|
+
authenticate,
|
|
36
|
+
authorize,
|
|
37
|
+
type AuthenticatedRequest,
|
|
38
|
+
} from "@medi-car-bd/mcb-shared-auth";
|
|
39
|
+
|
|
40
|
+
router.get("/employees", authenticate, authorize("HR_MANAGER"), handler);
|
|
41
|
+
|
|
42
|
+
const handler = (req: AuthenticatedRequest, res: Response) => {
|
|
43
|
+
const { sub: userId, role, tenantId } = req.user!;
|
|
44
|
+
// ...
|
|
45
|
+
};
|
|
11
46
|
```
|
|
12
47
|
|
|
13
|
-
|
|
48
|
+
`authenticate` accepts a `Bearer` token or an `x-access-token` header, and puts
|
|
49
|
+
the decoded claims on `req.user`. `authorize(...)` is a role guard that returns
|
|
50
|
+
`403` when the caller's `role` is not in the list. Called with no roles it
|
|
51
|
+
passes through, so it is safe to register unconditionally.
|
|
14
52
|
|
|
15
|
-
|
|
16
|
-
|
|
53
|
+
### Issue a token pair
|
|
54
|
+
|
|
55
|
+
Only the credential authority should call this. Persistence is yours to
|
|
56
|
+
provide:
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
import {
|
|
60
|
+
generateTokenPair,
|
|
61
|
+
type RefreshTokenRepository,
|
|
62
|
+
} from "@medi-car-bd/mcb-shared-auth";
|
|
63
|
+
|
|
64
|
+
const { accessToken, refreshToken } = await generateTokenPair({
|
|
65
|
+
user: { id, email, name, role, tenantId },
|
|
66
|
+
deviceInfo: req.headers["user-agent"],
|
|
67
|
+
ipAddress: req.ip,
|
|
68
|
+
config: {
|
|
69
|
+
jwtSecret: JWT_SECRET,
|
|
70
|
+
refreshTokenSecret: JWT_REFRESH_SECRET, // use a different secret
|
|
71
|
+
accessTokenExpiresIn: "15m",
|
|
72
|
+
refreshTokenExpiresIn: "7d",
|
|
73
|
+
},
|
|
74
|
+
repo: refreshTokenRepository, // your implementation
|
|
75
|
+
});
|
|
17
76
|
```
|
|
18
77
|
|
|
19
|
-
|
|
78
|
+
### Rotate a refresh token
|
|
20
79
|
|
|
21
|
-
```
|
|
22
|
-
|
|
80
|
+
```ts
|
|
81
|
+
const result = await rotateRefreshToken({ oldRefreshToken, config, repo });
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Rotation is single-use. Each refresh issues a new pair and marks the old token
|
|
85
|
+
`replacedBy`. Presenting an already-rotated token is treated as theft and
|
|
86
|
+
rejected, which is how a stolen refresh token gets surfaced instead of quietly
|
|
87
|
+
reused.
|
|
88
|
+
|
|
89
|
+
### Revoke everything for a user
|
|
23
90
|
|
|
91
|
+
```ts
|
|
92
|
+
await revokeAllUserTokens({ userId, reason: "password_change", repo });
|
|
24
93
|
```
|
|
25
94
|
|
|
26
|
-
-
|
|
95
|
+
Use this on password change and on admin-initiated lockouts. Pass
|
|
96
|
+
`excludeTokenId` to keep the current session alive.
|
|
27
97
|
|
|
28
|
-
|
|
29
|
-
|
|
98
|
+
## What is implemented
|
|
99
|
+
|
|
100
|
+
Every export below is available from the package root.
|
|
101
|
+
|
|
102
|
+
### Tokens
|
|
103
|
+
|
|
104
|
+
| Export | Purpose |
|
|
105
|
+
| ---------------------- | ----------------------------------------------------------------------- |
|
|
106
|
+
| `generateTokenPair` | Issue an access/refresh pair and persist the hashed refresh token |
|
|
107
|
+
| `generateAccessToken` | Sign an access token; includes `role` and `tenantId` when present |
|
|
108
|
+
| `generateRefreshToken` | Sign a refresh token, returning both the raw value and its SHA-256 hash |
|
|
109
|
+
| `rotateRefreshToken` | Single-use rotation with reuse detection |
|
|
110
|
+
| `revokeAllUserTokens` | Bulk revocation, optionally sparing the current session |
|
|
111
|
+
| `generateTokenId` | 32-byte random `jti` |
|
|
112
|
+
| `hashToken` | SHA-256 hex digest, for storing a token safely |
|
|
113
|
+
| `signToken` | Minimal signer driven by env vars, for simple cases |
|
|
114
|
+
|
|
115
|
+
Access tokens are signed with `audience: "mcb-services"` and `issuer:
|
|
116
|
+
"mcb-auth"`. Refresh tokens support a separate signing secret via
|
|
117
|
+
`config.refreshTokenSecret`, falling back to the access-token secret.
|
|
118
|
+
|
|
119
|
+
### Middleware
|
|
120
|
+
|
|
121
|
+
| Export | Purpose |
|
|
122
|
+
| ---------------- | ------------------------------------------------------- |
|
|
123
|
+
| `authenticate` | Verify a token and attach claims to `req.user` |
|
|
124
|
+
| `authorize` | Role guard: `authorize("ORG_ADMIN", "SUPER_ADMIN")` |
|
|
125
|
+
| `notFound` | `404` handler |
|
|
126
|
+
| `errorHandler` | Central error responder, normalising known error shapes |
|
|
127
|
+
| `processRequest` | Request logger that stamps the correlation id |
|
|
128
|
+
|
|
129
|
+
### Utilities
|
|
130
|
+
|
|
131
|
+
| Export | Purpose |
|
|
132
|
+
| ----------------- | ----------------------------------------------------------- |
|
|
133
|
+
| `comparePassword` | bcryptjs password comparison |
|
|
134
|
+
| `limiter` | `express-rate-limit` instance, 100 requests / 15 min |
|
|
135
|
+
| `AppError` | Operational error carrying an HTTP status |
|
|
136
|
+
| `catchAsync` | Wrap an async handler so rejections reach the error handler |
|
|
137
|
+
| `logger` | Winston logger with daily rotating files |
|
|
138
|
+
|
|
139
|
+
### Types
|
|
140
|
+
|
|
141
|
+
`AccessTokenPayload`, `RefreshTokenPayload`, `TokenConfig`, `TokenPair`,
|
|
142
|
+
`RefreshTokenRecord`, `RefreshTokenRepository`, `GenerateTokenPairParams`,
|
|
143
|
+
`RotateRefreshTokenParams`, `RotateRefreshTokenResult`,
|
|
144
|
+
`RevokeAllUserTokensParams`, `AuthenticatedRequest`, `TUser`.
|
|
145
|
+
|
|
146
|
+
## The repository interface
|
|
147
|
+
|
|
148
|
+
The package never touches a database. It calls the `RefreshTokenRepository`
|
|
149
|
+
interface, and the consuming service implements it:
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
interface RefreshTokenRepository {
|
|
153
|
+
create(record: RefreshTokenRecord): Promise<void>;
|
|
154
|
+
findById(id: string): Promise<RefreshTokenRecord | null>;
|
|
155
|
+
update(id: string, data: Partial<RefreshTokenRecord>): Promise<void>;
|
|
156
|
+
updateMany(where, data): Promise<{ count: number }>;
|
|
157
|
+
}
|
|
30
158
|
```
|
|
31
159
|
|
|
32
|
-
|
|
160
|
+
This is deliberate. A shared auth library that imported Prisma would force an
|
|
161
|
+
ORM on every consumer and would turn a security primitive into a data-access
|
|
162
|
+
layer. Keep it this way: implement the interface in the service that owns the
|
|
163
|
+
data, and let the other services stay stateless.
|
|
33
164
|
|
|
34
|
-
|
|
35
|
-
|
|
165
|
+
`findById` **must** return the related `user` with `id`, `email`, `name`,
|
|
166
|
+
`role` and `tenantId`. Rotation needs those claims to mint the replacement
|
|
167
|
+
access token, and it assumes they are present.
|
|
168
|
+
|
|
169
|
+
## Environment variables
|
|
170
|
+
|
|
171
|
+
Read at import time, so they must be set before the package is loaded.
|
|
172
|
+
|
|
173
|
+
| Variable | Used by | Notes |
|
|
174
|
+
| ---------------- | --------------------------- | ------------------------------- |
|
|
175
|
+
| `JWT_SECRET` | `authenticate`, `signToken` | **Required** |
|
|
176
|
+
| `JWT_EXPIRES_IN` | `signToken` | e.g. `15m` |
|
|
177
|
+
| `NODE_ENV` | `logger` | Selects console vs file logging |
|
|
178
|
+
|
|
179
|
+
Everything else — token lifetimes and the refresh secret — is passed explicitly
|
|
180
|
+
through `TokenConfig`, so there is no hidden global state.
|
|
181
|
+
|
|
182
|
+
## Recommendations
|
|
183
|
+
|
|
184
|
+
Ordered by how much they matter.
|
|
185
|
+
|
|
186
|
+
### 1. `authenticate` does not yet verify `audience` or `issuer`
|
|
36
187
|
|
|
188
|
+
Tokens are _issued_ with `aud` and `iss`, but `authenticate` verifies only the
|
|
189
|
+
signature and expiry. Because every service signs with one shared secret, a
|
|
190
|
+
token minted for any other purpose is currently accepted anywhere.
|
|
191
|
+
|
|
192
|
+
The fix is three lines inside `authenticate`, and it belongs here rather than in
|
|
193
|
+
each consumer so that all callers get it at once:
|
|
194
|
+
|
|
195
|
+
```ts
|
|
196
|
+
jwt.verify(token, String(JWT_SECRET), {
|
|
197
|
+
audience: "mcb-services",
|
|
198
|
+
issuer: "mcb-auth",
|
|
199
|
+
});
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Tracked, not yet applied.
|
|
203
|
+
|
|
204
|
+
### 2. Fail fast on a missing `JWT_SECRET`
|
|
205
|
+
|
|
206
|
+
`authenticate` calls `String(JWT_SECRET)`, which turns an unset variable into
|
|
207
|
+
the literal string `"undefined"` and silently accepts tokens signed with it.
|
|
208
|
+
Validate the secret at startup and exit instead:
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
if (!JWT_SECRET) throw new Error("JWT_SECRET is not configured");
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### 3. Use a separate refresh-token secret
|
|
215
|
+
|
|
216
|
+
Set `refreshTokenSecret` to a different value from `jwtSecret`. Otherwise
|
|
217
|
+
leaking the access-token signing key also lets an attacker mint refresh tokens
|
|
218
|
+
with any `sub`, which is a complete account takeover.
|
|
219
|
+
|
|
220
|
+
### 4. Strip stack traces from error responses in production
|
|
221
|
+
|
|
222
|
+
`errorHandler` always includes `stack` in the JSON body. Gate it on `NODE_ENV`
|
|
223
|
+
before exposing the library publicly.
|
|
224
|
+
|
|
225
|
+
### 5. Avoid `processRequest` on credential routes
|
|
226
|
+
|
|
227
|
+
`processRequest` serialises `req.body` into the log file. On a login or
|
|
228
|
+
register route that writes plaintext passwords to disk. Either drop body
|
|
229
|
+
logging or skip that middleware on those routes.
|
|
230
|
+
|
|
231
|
+
### 6. Swap the in-memory limiter for Redis when you run more than one instance
|
|
232
|
+
|
|
233
|
+
`limiter` keeps counters in process memory, so with N replicas each one
|
|
234
|
+
effectively allows N times the configured rate. The message it returns also
|
|
235
|
+
promises "in an hour" while the window is 15 minutes.
|
|
236
|
+
|
|
237
|
+
```ts
|
|
238
|
+
import { RedisStore } from "rate-limit-redis";
|
|
239
|
+
import { rateLimit } from "express-rate-limit";
|
|
240
|
+
|
|
241
|
+
rateLimit({
|
|
242
|
+
windowMs: 15 * 60 * 1000,
|
|
243
|
+
limit: 100,
|
|
244
|
+
store: new RedisStore({
|
|
245
|
+
prefix: "rl:",
|
|
246
|
+
sendCommand: (...a) => redis.call(...a),
|
|
247
|
+
}),
|
|
248
|
+
});
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Also set `app.set("trust proxy", ...)` behind a load balancer, or every caller
|
|
252
|
+
shares the proxy's address and per-IP limiting stops working.
|
|
253
|
+
|
|
254
|
+
### 7. Prefer asynchronous password comparison
|
|
255
|
+
|
|
256
|
+
`comparePassword` uses `compareSync`, which blocks the event loop. That is
|
|
257
|
+
visible under login load. Switch to `bcryptjs.compare` when you need throughput.
|
|
258
|
+
|
|
259
|
+
### 8. Short access-token lifetime plus rotation
|
|
260
|
+
|
|
261
|
+
`15m` access tokens with `7d` rotating refresh tokens keeps the blast radius of
|
|
262
|
+
a leaked access token small, and rotation makes reuse detectable. Long-lived
|
|
263
|
+
access tokens remove both properties.
|
|
264
|
+
|
|
265
|
+
### Housekeeping
|
|
266
|
+
|
|
267
|
+
- `types/jwt.ts` still documents a `TokenUser` type that no longer exists
|
|
268
|
+
(removed in `0.0.8`); the shapes are inline.
|
|
269
|
+
- `TUser` and `TGenerateSKU` are boilerplate leftovers and unused by the
|
|
270
|
+
platform.
|
|
271
|
+
- `authorize` is typed `Array<string | number>` but only ever compares a string
|
|
272
|
+
`role`.
|
|
273
|
+
|
|
274
|
+
## Publishing
|
|
275
|
+
|
|
276
|
+
```bash
|
|
277
|
+
pnpm build # must run first: package.json "files" is ["dist"]
|
|
37
278
|
npm version patch
|
|
279
|
+
npm publish --access public
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
The package is scoped `@medi-car-bd` and `publishConfig.access` is already
|
|
283
|
+
`public`, so `--access public` is belt-and-braces.
|
|
284
|
+
|
|
285
|
+
To authenticate, use an automation token rather than a long-lived personal one:
|
|
38
286
|
|
|
287
|
+
```bash
|
|
39
288
|
npm config set //registry.npmjs.org/:_authToken=npm_xxxxxxxxxxxxxxxxx
|
|
289
|
+
```
|
|
40
290
|
|
|
41
|
-
|
|
291
|
+
## Development
|
|
42
292
|
|
|
43
|
-
|
|
293
|
+
```bash
|
|
294
|
+
pnpm install
|
|
295
|
+
pnpm typecheck
|
|
296
|
+
pnpm lint
|
|
297
|
+
pnpm build
|
|
44
298
|
```
|
|
299
|
+
|
|
300
|
+
## License
|
|
301
|
+
|
|
302
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,64 +1,77 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@medi-car-bd/mcb-shared-auth",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "Shared authentication module for MCB applications",
|
|
5
|
-
"packageManager": "pnpm@10.18.0",
|
|
6
|
-
"main": "dist/index.js",
|
|
7
|
-
"types": "dist/index.d.ts",
|
|
8
|
-
"publishConfig": {
|
|
9
|
-
"access": "public"
|
|
10
|
-
},
|
|
11
|
-
"scripts": {
|
|
12
|
-
"preinstall": "node -e \"\"",
|
|
13
|
-
"postinstall": "",
|
|
14
|
-
"build": "tsc",
|
|
15
|
-
"start": "node dist/index.js",
|
|
16
|
-
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
17
|
-
"lint": "eslint . --ext .ts,.tsx,.js,.jsx",
|
|
18
|
-
"lint:fix": "eslint . --ext .ts,.tsx,.js,.jsx --fix",
|
|
19
|
-
"format": "prettier --write .",
|
|
20
|
-
"format:check": "prettier --check ."
|
|
21
|
-
},
|
|
22
|
-
"keywords": [
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
"
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
"
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
"
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@medi-car-bd/mcb-shared-auth",
|
|
3
|
+
"version": "0.0.15",
|
|
4
|
+
"description": "Shared authentication module for MCB applications",
|
|
5
|
+
"packageManager": "pnpm@10.18.0",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"publishConfig": {
|
|
9
|
+
"access": "public"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"preinstall": "node -e \"\"",
|
|
13
|
+
"postinstall": "",
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"start": "node dist/index.js",
|
|
16
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
17
|
+
"lint": "eslint . --ext .ts,.tsx,.js,.jsx",
|
|
18
|
+
"lint:fix": "eslint . --ext .ts,.tsx,.js,.jsx --fix",
|
|
19
|
+
"format": "prettier --write .",
|
|
20
|
+
"format:check": "prettier --check ."
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"jwt",
|
|
24
|
+
"authentication",
|
|
25
|
+
"express",
|
|
26
|
+
"authorization",
|
|
27
|
+
"token-rotation"
|
|
28
|
+
],
|
|
29
|
+
"author": {
|
|
30
|
+
"name": "Medi-Car-BD",
|
|
31
|
+
"url": "https://github.com/mcb-org"
|
|
32
|
+
},
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/bcryptjs": "^2.4.6",
|
|
36
|
+
"@types/express": "^4.17.21",
|
|
37
|
+
"@types/jsonwebtoken": "^9.0.5",
|
|
38
|
+
"@types/node": "^20.11.0",
|
|
39
|
+
"@typescript-eslint/eslint-plugin": "^8.54.0",
|
|
40
|
+
"@typescript-eslint/parser": "^8.54.0",
|
|
41
|
+
"eslint": "^9.39.2",
|
|
42
|
+
"eslint-config-prettier": "^9.1.0",
|
|
43
|
+
"prettier": "^3.2.5",
|
|
44
|
+
"typescript": "^5.3.3"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"bcryptjs": "^2.4.3",
|
|
48
|
+
"dotenv": "^16.3.1",
|
|
49
|
+
"express-rate-limit": "^7.1.5",
|
|
50
|
+
"jsonwebtoken": "^9.0.2",
|
|
51
|
+
"winston": "^3.11.0",
|
|
52
|
+
"winston-daily-rotate-file": "^4.7.1"
|
|
53
|
+
},
|
|
54
|
+
"peerDependencies": {
|
|
55
|
+
"express": "^4.18.2"
|
|
56
|
+
},
|
|
57
|
+
"files": [
|
|
58
|
+
"dist"
|
|
59
|
+
],
|
|
60
|
+
"lint-staged": {
|
|
61
|
+
"*.{ts,tsx,js,jsx}": [
|
|
62
|
+
"eslint --max-warnings=0 --fix",
|
|
63
|
+
"prettier --write"
|
|
64
|
+
],
|
|
65
|
+
"*.{json,md,yml,yaml}": [
|
|
66
|
+
"prettier --write"
|
|
67
|
+
]
|
|
68
|
+
},
|
|
69
|
+
"repository": {
|
|
70
|
+
"type": "git",
|
|
71
|
+
"url": "git+https://github.com/mcb-org/mcb-shared-auth.git"
|
|
72
|
+
},
|
|
73
|
+
"homepage": "https://github.com/mcb-org/mcb-shared-auth#readme",
|
|
74
|
+
"bugs": {
|
|
75
|
+
"url": "https://github.com/mcb-org/mcb-shared-auth/issues"
|
|
76
|
+
}
|
|
77
|
+
}
|