dauth-md-node 4.0.0 → 5.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/README.md CHANGED
@@ -1,16 +1,37 @@
1
1
  # dauth-md-node
2
2
 
3
- Express middleware for JWT-based authentication against the [Dauth](https://dauth.ovh) service. Verifies tenant JWTs and fetches the authenticated user from the Dauth backend, attaching it to `req.user`.
3
+ Express middleware and router for JWT-based authentication against the [dauth](https://dauth.ovh) service. Two exports: `dauth()` middleware that verifies JWTs (via Authorization header or encrypted session cookies) and attaches `req.user`, and `dauthRouter()` that provides pre-built session-based auth routes with encrypted cookies, CSRF protection, and automatic token refresh.
4
4
 
5
5
  ## Installation
6
6
 
7
7
  ```bash
8
8
  npm install dauth-md-node
9
9
  # or
10
- yarn add dauth-md-node
10
+ pnpm add dauth-md-node
11
11
  ```
12
12
 
13
- ## Quick Start
13
+ For session cookie mode or the router, also install `cookie-parser`:
14
+
15
+ ```bash
16
+ pnpm add cookie-parser
17
+ ```
18
+
19
+ ## Tech Stack
20
+
21
+ | Technology | Version | Purpose |
22
+ |---|---|---|
23
+ | Node.js | >= 18 | Runtime (native fetch required) |
24
+ | TypeScript | 5.9 | Type safety |
25
+ | jsonwebtoken | 9 | JWT verification (runtime dependency) |
26
+ | Express | 4.18+ / 5 | Peer dependency |
27
+ | cookie-parser | 1.4+ | Optional peer dependency (session/router mode) |
28
+ | tsup | 8 | Build tool (CJS + ESM bundles, two entry points) |
29
+ | vitest | 4 | Testing framework |
30
+ | size-limit | 12 | Bundle size budget (10KB per entry) |
31
+
32
+ ## Usage
33
+
34
+ ### Middleware (Authorization header mode)
14
35
 
15
36
  ```typescript
16
37
  import express from 'express';
@@ -18,186 +39,192 @@ import { dauth, IRequestDauth } from 'dauth-md-node';
18
39
 
19
40
  const app = express();
20
41
 
21
- // Apply DAuth middleware to protected routes
22
42
  const dauthMiddleware = dauth({
23
43
  domainName: 'your-domain-name',
24
44
  tsk: 'your-tenant-secret-key',
25
45
  });
26
46
 
27
47
  app.get('/api/protected', dauthMiddleware, (req, res) => {
28
- // req.user is populated with the authenticated user object
29
- res.json({ user: req.user });
48
+ res.json({ user: (req as IRequestDauth).user });
30
49
  });
50
+ ```
51
+
52
+ ### Middleware (session cookie mode)
53
+
54
+ ```typescript
55
+ import express from 'express';
56
+ import cookieParser from 'cookie-parser';
57
+ import { dauth } from 'dauth-md-node';
31
58
 
32
- app.listen(4000);
59
+ const app = express();
60
+ app.use(cookieParser());
61
+
62
+ const dauthMiddleware = dauth({
63
+ domainName: 'your-domain-name',
64
+ tsk: 'your-tenant-secret-key',
65
+ session: {},
66
+ });
67
+
68
+ app.get('/api/protected', dauthMiddleware, (req, res) => {
69
+ res.json({ user: req.user });
70
+ });
33
71
  ```
34
72
 
35
- ## API
73
+ ### Router (session-based auth routes)
74
+
75
+ ```typescript
76
+ import express from 'express';
77
+ import cookieParser from 'cookie-parser';
78
+ import { dauthRouter } from 'dauth-md-node/router';
36
79
 
37
- ### `dauth(options)`
80
+ const app = express();
81
+ app.use(express.json());
82
+ app.use(cookieParser());
38
83
 
39
- Factory function that returns an Express middleware.
84
+ app.use('/api/auth', dauthRouter({
85
+ domainName: 'your-domain-name',
86
+ tsk: 'your-tenant-secret-key',
87
+ }));
88
+
89
+ // Available routes:
90
+ // POST /api/auth/exchange-code
91
+ // GET /api/auth/session
92
+ // POST /api/auth/logout (CSRF required)
93
+ // PATCH /api/auth/user (CSRF required)
94
+ // DELETE /api/auth/user (CSRF required)
95
+ // GET /api/auth/profile-redirect (CSRF required)
96
+ ```
40
97
 
41
- | Parameter | Type | Description |
42
- |---|---|---|
43
- | `domainName` | `string` | Your Dauth domain name (used for API routing) |
44
- | `tsk` | `string` | Tenant Secret Key for local JWT verification |
98
+ ## API Reference
45
99
 
46
- ### Middleware Behavior
100
+ ### `dauth(options: DauthOptions)`
47
101
 
48
- 1. Extracts the `Authorization` header from the request
49
- 2. Verifies the JWT locally using the provided `tsk` (Tenant Secret Key)
50
- 3. Fetches the full user object from the Dauth backend (`GET /app/:domainName/user`)
51
- 4. Attaches the user to `req.user`
52
- 5. Calls `next()` on success
102
+ Returns an Express middleware.
53
103
 
54
- ### Error Responses
104
+ | Parameter | Type | Required | Default | Description |
105
+ |---|---|---|---|---|
106
+ | `domainName` | `string` | yes | - | Tenant identifier (used in API path) |
107
+ | `tsk` | `string` | yes | - | Tenant Secret Key for JWT verification |
108
+ | `cache` | `{ ttlMs: number }` | no | - | Enable in-memory user cache with TTL |
109
+ | `session` | `SessionOptions` | no | - | Enable session cookie mode |
55
110
 
56
- | Scenario | Status | Response Status Field |
57
- |---|---|---|
58
- | Missing `Authorization` header | 403 | `token-not-found` |
59
- | JWT expired | 401 | `token-expired` |
60
- | Invalid JWT or bad TSK | 401 | `tsk-not-invalid` or `token-invalid` |
61
- | User not found in Dauth backend | 404 | `user-not-found` |
62
- | Dauth backend server error | 500 | `error` |
63
- | Other backend status | 501 | `request-error` |
111
+ **SessionOptions:**
64
112
 
65
- ### `req.user` Object
113
+ | Parameter | Type | Default | Description |
114
+ |---|---|---|---|
115
+ | `cookieName` | `string` | `__Host-dauth-session` (prod) / `dauth-session` (dev) | Session cookie name |
116
+ | `secure` | `boolean` | `true` (except `NODE_ENV=development`) | Cookie `Secure` flag |
117
+ | `previousTsk` | `string` | - | Previous TSK for zero-downtime key rotation |
118
+ | `sessionSalt` | `string` | built-in default | Custom HKDF salt (hex string) |
66
119
 
67
- When authentication succeeds, `req.user` contains:
120
+ **Without `session`**: extracts `Authorization` header, verifies JWT with `tsk`, fetches user from dauth backend, attaches to `req.user`.
68
121
 
69
- ```typescript
70
- interface IDauthUser {
71
- _id: string;
72
- name: string;
73
- lastname: string;
74
- nickname: string;
75
- email: string;
76
- isVerified: boolean;
77
- language: string;
78
- avatar: { id: string; url: string };
79
- role: string;
80
- telPrefix: string;
81
- telSuffix: string;
82
- createdAt: Date;
83
- updatedAt: Date;
84
- lastLogin: Date;
85
- }
86
- ```
122
+ **With `session`**: reads encrypted session cookie, decrypts with key derived from `tsk` (falls back to `previousTsk`), extracts access token, verifies JWT, fetches user, attaches to `req.user`.
87
123
 
88
- Both `IDauthUser` and `IRequestDauth` are exported from the package for type-safe usage in consumer code.
124
+ ### `dauthRouter(options: DauthRouterOptions)`
89
125
 
90
- ## Real-World Integration Example
126
+ Returns an Express Router. Requires `cookie-parser` middleware. Import from `dauth-md-node/router`.
91
127
 
92
- This is the pattern used in `easymediacloud-backend-node`, which delegates all user authentication to Dauth.
128
+ | Parameter | Type | Default | Description |
129
+ |---|---|---|---|
130
+ | `domainName` | `string` | (required) | Tenant identifier |
131
+ | `tsk` | `string` | (required) | Tenant Secret Key |
132
+ | `dauthUrl` | `string` | auto-detected | Override dauth backend URL |
133
+ | `cookieName` | `string` | `__Host-dauth-session` / `dauth-session` | Session cookie name |
134
+ | `csrfCookieName` | `string` | `__Host-csrf` / `csrf-token` | CSRF cookie name |
135
+ | `maxAge` | `number` | `2592000` (30 days) | Cookie max age in seconds |
136
+ | `secure` | `boolean` | `true` (except dev) | Cookie `Secure` flag |
137
+ | `previousTsk` | `string` | - | Previous TSK for key rotation |
138
+ | `sessionSalt` | `string` | built-in default | Custom HKDF salt (hex string) |
93
139
 
94
- ### 1. Initialize the middleware from environment variables
140
+ **Router routes:**
95
141
 
96
- ```typescript
97
- // src/middlewares/auth.middleware.ts
98
- import { dauth, IRequestDauth } from 'dauth-md-node';
99
- import config from '../config/config';
142
+ | Method | Path | CSRF | Description |
143
+ |---|---|---|---|
144
+ | `POST` | `/exchange-code` | No | Exchange auth code for session, set cookies, return `{ user, domain, isNewUser }` |
145
+ | `GET` | `/session` | No | Check session, auto-refresh if token expires within 5min, return `{ user, domain }` |
146
+ | `POST` | `/logout` | Yes | Revoke refresh token (fire-and-forget), clear cookies |
147
+ | `PATCH` | `/user` | Yes | Proxy user update to dauth backend with auto-refresh |
148
+ | `DELETE` | `/user` | Yes | Delete user account, clear cookies |
149
+ | `GET` | `/profile-redirect` | Yes | Generate profile code, return `{ redirectUrl }` |
100
150
 
101
- export const dauth_md = dauth({
102
- tsk: config.dauth.TSK as string,
103
- domainName: config.dauth.DOMAIN_NAME as string,
104
- });
105
- ```
151
+ CSRF uses the double-submit cookie pattern: `POST /exchange-code` sets a CSRF cookie (`httpOnly: false`), and subsequent state-changing requests must include the cookie value as the `x-csrf-token` header.
106
152
 
107
- Environment variables (`.env.development`):
108
- ```
109
- DAUTH_TSK=your-tenant-secret-key
110
- DAUTH_DOMAIN_NAME=your-domain-name
111
- ```
153
+ ### Exported types (from `dauth-md-node`)
112
154
 
113
- ### 2. Build custom middleware chains on top
155
+ - `IDauthUser` -- user object (name, email, avatar, role, language, authMethods, etc.)
156
+ - `AuthMethodType` -- `'magic-link' | 'passkey'`
157
+ - `IRequestDauth` -- extends Express `Request` with `user: IDauthUser`
158
+ - `DauthOptions` -- middleware factory options
159
+ - `SessionOptions` -- session cookie configuration
160
+ - `UserCache` -- cache class (for direct usage/testing)
161
+ - `CacheOptions` -- cache configuration type
114
162
 
115
- After `dauth_md` populates `req.user`, add your own guards:
163
+ ### Exported types (from `dauth-md-node/router`)
116
164
 
117
- ```typescript
118
- // src/middlewares/auth.middleware.ts (continued)
119
- import { Response, NextFunction } from 'express';
120
-
121
- export const is_verified = async (req: IRequestDauth, res: Response, next: NextFunction) => {
122
- if (req.user.isVerified === false) {
123
- return res.status(401).send({ status: 'not-verified', message: 'Email not verified' });
124
- }
125
- next();
126
- };
127
-
128
- export const ensure_admin = async (req: IRequestDauth, res: Response, next: NextFunction) => {
129
- if (req.user.isVerified === false) {
130
- return res.status(401).send({ status: 'not-verified', message: 'Email not verified' });
131
- }
132
- if (req.user.role !== 'admin') {
133
- return res.status(401).send({ status: 'not-admin', message: 'Admin role required' });
134
- }
135
- next();
136
- };
137
- ```
165
+ - `DauthRouterOptions` -- router factory options
138
166
 
139
- ### 3. Apply middleware chains to routes
167
+ ### Environment detection
140
168
 
141
- ```typescript
142
- // src/core/licenses/router/licenses.router.ts
143
- import { Router } from 'express';
144
- import { dauth_md, is_verified, ensure_admin } from '../../../middlewares/auth.middleware';
145
- import * as controller from '../controllers/licenses.controller';
169
+ The middleware resolves the dauth backend URL in this order:
146
170
 
147
- const licenseApi = Router();
171
+ 1. `DAUTH_URL` environment variable
172
+ 2. `NODE_ENV=development` -> `http://localhost:4012/api/v1`
173
+ 3. Default -> `https://dauth.ovh/api/v1`
148
174
 
149
- licenseApi
150
- .post('/create-license', [dauth_md, is_verified], controller.createLicense)
151
- .get('/get-my-licenses', [dauth_md, is_verified], controller.getMyLicenses)
152
- .patch('/enable-license/:licenseId', [dauth_md, ensure_admin], controller.enableLicense)
153
- .delete('/delete-license/:licenseId', [dauth_md, is_verified], controller.deleteLicense);
175
+ The router also accepts `dauthUrl` in options, which takes priority over the env var.
154
176
 
155
- export default licenseApi;
156
- ```
177
+ ### Error responses (middleware)
157
178
 
158
- ### 4. Access the user in controllers
179
+ | Scenario | Status | Status Field |
180
+ |---|---|---|
181
+ | Missing `Authorization` header (header mode) | 403 | `token-not-found` |
182
+ | Missing session cookie (session mode) | 401 | `no-session` |
183
+ | Invalid/undecryptable session cookie | 401 | `session-invalid` |
184
+ | JWT expired | 401 | `token-expired` |
185
+ | Invalid JWT or bad TSK | 401 | `tsk-not-invalid` / `token-invalid` |
186
+ | User not found | 404 | `user-not-found` |
187
+ | Backend server error | 500 | `error` |
188
+ | Other backend status | 501 | `request-error` |
159
189
 
160
- ```typescript
161
- // src/core/licenses/controllers/licenses.controller.ts
162
- export const getMyLicenses = async (req: IRequestDauth, res: Response) => {
163
- const userId = req.user._id;
164
- const licenses = await License.find({ user: userId });
165
- res.status(200).json({ status: 'success', data: licenses });
166
- };
167
- ```
190
+ ## Scripts
168
191
 
169
- ## Environment Detection
192
+ | Script | Description |
193
+ |---|---|
194
+ | `pnpm start` | Watch mode (tsup --watch) |
195
+ | `pnpm build` | Production build (CJS + ESM + types, two entry points) |
196
+ | `pnpm test` | Run vitest tests (80 tests) |
197
+ | `pnpm test:coverage` | Coverage report (v8, 70% threshold) |
198
+ | `pnpm typecheck` | TypeScript type checking |
199
+ | `pnpm size` | Check bundle size (10KB budget per entry) |
200
+ | `pnpm format` | Prettier formatting |
170
201
 
171
- - **Development** (`NODE_ENV=development`): Routes API calls to `http://localhost:4012/api/v1`
172
- - **Production**: Routes API calls to `https://dauth.ovh/api/v1`
202
+ ## Testing
173
203
 
174
- ## Development
204
+ 80 tests across 7 files using vitest 4 (node environment).
175
205
 
176
206
  ```bash
177
- pnpm start # Watch mode (tsdx watch)
178
- pnpm build # Production build (CJS + ESM)
179
- pnpm test # Run Jest tests
180
- pnpm lint # ESLint via tsdx
181
- pnpm size # Check bundle size (10KB budget per entry)
182
- pnpm analyze # Bundle size analysis with visualization
207
+ pnpm test
208
+ pnpm test:coverage
183
209
  ```
184
210
 
185
- ### Bundle Outputs
211
+ ## Publishing
186
212
 
187
- - **CJS:** `dist/index.js` (with `.development.js` and `.production.min.js` variants)
188
- - **ESM:** `dist/dauth-md-node.esm.js`
189
- - **Types:** `dist/index.d.ts`
213
+ Automated via GitHub Actions. Push a `v*` tag to trigger build, test, and `npm publish`.
190
214
 
191
- ## Dependencies
215
+ ```bash
216
+ # 1. Bump version in package.json
217
+ # 2. Commit and tag
218
+ git tag v4.0.1
219
+ git push origin main --tags
220
+ # 3. GitHub Actions publishes to npm automatically
221
+ ```
192
222
 
193
- - `express` >= 4
194
- - `jsonwebtoken` >= 9
195
- - `mongoose` >= 8
196
- - `node-fetch` ^2.6
223
+ Requires `NPM_TOKEN` secret configured in the GitHub repo.
197
224
 
198
- ## Author
225
+ ## Code Style
199
226
 
200
- David T. Pizarro Frick
227
+ Prettier: 80 char width, single quotes, semicolons, trailing commas (es5), 2-space indent.
201
228
 
202
229
  ## License
203
230
 
@@ -79,4 +79,4 @@ export {
79
79
  encryptSession,
80
80
  decryptSessionWithKeys
81
81
  };
82
- //# sourceMappingURL=chunk-4A7BR4EM.mjs.map
82
+ //# sourceMappingURL=chunk-RKH7YKIR.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/api/utils/config.ts","../src/session.ts"],"sourcesContent":["export const apiVersion = 'v1';\nexport const serverDomain = 'dauth.ovh';\n\nexport function getServerBasePath(): string {\n if (process.env.DAUTH_URL) {\n const base = process.env.DAUTH_URL.replace(/\\/+$/, '');\n return `${base}/api/${apiVersion}`;\n }\n\n const isLocalhost = process.env.NODE_ENV === 'development';\n const serverPort = 4012;\n const serverLocalUrl = `http://localhost:${serverPort}/api/${apiVersion}`;\n const serverProdUrl = `https://${serverDomain}/api/${apiVersion}`;\n return isLocalhost ? serverLocalUrl : serverProdUrl;\n}\n","import crypto from 'crypto';\n\nexport interface SessionPayload {\n accessToken: string;\n refreshToken: string;\n}\n\nconst INFO = 'dauth-cookie-enc-v1';\nconst DEFAULT_SALT = Buffer.from(\n 'a3f8c1d7e9b24f6081c5d3a7e2f49b0653d81f7a2e94c0b6d8f3a5e1c7b09d42',\n 'hex'\n);\n\nexport async function deriveEncryptionKey(\n tsk: string,\n salt?: string\n): Promise<Buffer> {\n const saltBuf = salt ? Buffer.from(salt, 'hex') : DEFAULT_SALT;\n return new Promise((resolve, reject) => {\n crypto.hkdf(\n 'sha256',\n Buffer.from(tsk),\n saltBuf,\n INFO,\n 32,\n (err, derivedKey) => {\n if (err) return reject(err);\n resolve(Buffer.from(derivedKey));\n }\n );\n });\n}\n\nexport function encryptSession(payload: SessionPayload, key: Buffer): string {\n const nonce = crypto.randomBytes(12);\n const cipher = crypto.createCipheriv('aes-256-gcm', key, nonce);\n const plaintext = JSON.stringify(payload);\n const encrypted = Buffer.concat([\n cipher.update(plaintext, 'utf8'),\n cipher.final(),\n ]);\n const authTag = cipher.getAuthTag();\n // Format: base64(nonce + ciphertext + authTag)\n return Buffer.concat([nonce, encrypted, authTag]).toString('base64');\n}\n\nexport function decryptSession(\n ciphertext: string,\n key: Buffer\n): SessionPayload | null {\n try {\n const buf = Buffer.from(ciphertext, 'base64');\n if (buf.length < 12 + 16) return null; // nonce(12) + authTag(16) minimum\n const nonce = buf.subarray(0, 12);\n const authTag = buf.subarray(buf.length - 16);\n const encrypted = buf.subarray(12, buf.length - 16);\n const decipher = crypto.createDecipheriv('aes-256-gcm', key, nonce);\n decipher.setAuthTag(authTag);\n const decrypted = Buffer.concat([\n decipher.update(encrypted),\n decipher.final(),\n ]);\n return JSON.parse(decrypted.toString('utf8')) as SessionPayload;\n } catch {\n return null;\n }\n}\n\nexport function decryptSessionWithKeys(\n ciphertext: string,\n keys: Buffer[]\n): SessionPayload | null {\n for (const key of keys) {\n const result = decryptSession(ciphertext, key);\n if (result) return result;\n }\n return null;\n}\n"],"mappings":";AAAO,IAAM,aAAa;AACnB,IAAM,eAAe;AAErB,SAAS,oBAA4B;AAC1C,MAAI,QAAQ,IAAI,WAAW;AACzB,UAAM,OAAO,QAAQ,IAAI,UAAU,QAAQ,QAAQ,EAAE;AACrD,WAAO,GAAG,IAAI,QAAQ,UAAU;AAAA,EAClC;AAEA,QAAM,cAAc,QAAQ,IAAI,aAAa;AAC7C,QAAM,aAAa;AACnB,QAAM,iBAAiB,oBAAoB,UAAU,QAAQ,UAAU;AACvE,QAAM,gBAAgB,WAAW,YAAY,QAAQ,UAAU;AAC/D,SAAO,cAAc,iBAAiB;AACxC;;;ACdA,OAAO,YAAY;AAOnB,IAAM,OAAO;AACb,IAAM,eAAe,OAAO;AAAA,EAC1B;AAAA,EACA;AACF;AAEA,eAAsB,oBACpB,KACA,MACiB;AACjB,QAAM,UAAU,OAAO,OAAO,KAAK,MAAM,KAAK,IAAI;AAClD,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,WAAO;AAAA,MACL;AAAA,MACA,OAAO,KAAK,GAAG;AAAA,MACf;AAAA,MACA;AAAA,MACA;AAAA,MACA,CAAC,KAAK,eAAe;AACnB,YAAI,IAAK,QAAO,OAAO,GAAG;AAC1B,gBAAQ,OAAO,KAAK,UAAU,CAAC;AAAA,MACjC;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEO,SAAS,eAAe,SAAyB,KAAqB;AAC3E,QAAM,QAAQ,OAAO,YAAY,EAAE;AACnC,QAAM,SAAS,OAAO,eAAe,eAAe,KAAK,KAAK;AAC9D,QAAM,YAAY,KAAK,UAAU,OAAO;AACxC,QAAM,YAAY,OAAO,OAAO;AAAA,IAC9B,OAAO,OAAO,WAAW,MAAM;AAAA,IAC/B,OAAO,MAAM;AAAA,EACf,CAAC;AACD,QAAM,UAAU,OAAO,WAAW;AAElC,SAAO,OAAO,OAAO,CAAC,OAAO,WAAW,OAAO,CAAC,EAAE,SAAS,QAAQ;AACrE;AAEO,SAAS,eACd,YACA,KACuB;AACvB,MAAI;AACF,UAAM,MAAM,OAAO,KAAK,YAAY,QAAQ;AAC5C,QAAI,IAAI,SAAS,KAAK,GAAI,QAAO;AACjC,UAAM,QAAQ,IAAI,SAAS,GAAG,EAAE;AAChC,UAAM,UAAU,IAAI,SAAS,IAAI,SAAS,EAAE;AAC5C,UAAM,YAAY,IAAI,SAAS,IAAI,IAAI,SAAS,EAAE;AAClD,UAAM,WAAW,OAAO,iBAAiB,eAAe,KAAK,KAAK;AAClE,aAAS,WAAW,OAAO;AAC3B,UAAM,YAAY,OAAO,OAAO;AAAA,MAC9B,SAAS,OAAO,SAAS;AAAA,MACzB,SAAS,MAAM;AAAA,IACjB,CAAC;AACD,WAAO,KAAK,MAAM,UAAU,SAAS,MAAM,CAAC;AAAA,EAC9C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,uBACd,YACA,MACuB;AACvB,aAAW,OAAO,MAAM;AACtB,UAAM,SAAS,eAAe,YAAY,GAAG;AAC7C,QAAI,OAAQ,QAAO;AAAA,EACrB;AACA,SAAO;AACT;","names":[]}
package/dist/index.d.mts CHANGED
@@ -1,5 +1,39 @@
1
1
  import { Request, Response, NextFunction } from 'express';
2
2
 
3
+ interface TenantUser {
4
+ _id: string;
5
+ name: string;
6
+ lastname: string;
7
+ email: string;
8
+ avatar: {
9
+ id: string;
10
+ url: string;
11
+ };
12
+ }
13
+ interface TenantUserResponse {
14
+ response: {
15
+ status: number;
16
+ };
17
+ data: {
18
+ status?: string;
19
+ data?: TenantUser | null;
20
+ message?: string;
21
+ };
22
+ }
23
+ interface BatchUsersResponse {
24
+ response: {
25
+ status: number;
26
+ };
27
+ data: {
28
+ status?: string;
29
+ data?: TenantUser[];
30
+ message?: string;
31
+ };
32
+ }
33
+ declare function searchUserByEmail(token: string, domainName: string, email: string): Promise<TenantUserResponse>;
34
+ declare function getUserById(token: string, domainName: string, userId: string): Promise<TenantUserResponse>;
35
+ declare function batchGetUsers(token: string, domainName: string, userIds: string[]): Promise<BatchUsersResponse>;
36
+
3
37
  interface CacheOptions {
4
38
  ttlMs: number;
5
39
  }
@@ -39,6 +73,7 @@ interface IDauthUser {
39
73
  }
40
74
  interface IRequestDauth extends Request {
41
75
  user: IDauthUser;
76
+ dauthToken: string;
42
77
  files: {
43
78
  image: {
44
79
  path: string;
@@ -68,6 +103,6 @@ interface TCustomResponse extends Response {
68
103
  send(body?: unknown): this;
69
104
  }
70
105
 
71
- declare const dauth: ({ domainName, tsk, cache, session, }: DauthOptions) => (req: IRequestDauth, res: TCustomResponse, next: NextFunction) => Promise<void | TCustomResponse>;
106
+ declare const dauth: ({ domainName, tsk, cache, session }: DauthOptions) => (req: IRequestDauth, res: TCustomResponse, next: NextFunction) => Promise<void | TCustomResponse>;
72
107
 
73
- export { type AuthMethodType, type CacheOptions, type DauthOptions, type IDauthUser, type IRequestDauth, type SessionOptions, UserCache, dauth };
108
+ export { type AuthMethodType, type CacheOptions, type DauthOptions, type IDauthUser, type IRequestDauth, type SessionOptions, type TenantUser, UserCache, batchGetUsers, dauth, getUserById, searchUserByEmail };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,39 @@
1
1
  import { Request, Response, NextFunction } from 'express';
2
2
 
3
+ interface TenantUser {
4
+ _id: string;
5
+ name: string;
6
+ lastname: string;
7
+ email: string;
8
+ avatar: {
9
+ id: string;
10
+ url: string;
11
+ };
12
+ }
13
+ interface TenantUserResponse {
14
+ response: {
15
+ status: number;
16
+ };
17
+ data: {
18
+ status?: string;
19
+ data?: TenantUser | null;
20
+ message?: string;
21
+ };
22
+ }
23
+ interface BatchUsersResponse {
24
+ response: {
25
+ status: number;
26
+ };
27
+ data: {
28
+ status?: string;
29
+ data?: TenantUser[];
30
+ message?: string;
31
+ };
32
+ }
33
+ declare function searchUserByEmail(token: string, domainName: string, email: string): Promise<TenantUserResponse>;
34
+ declare function getUserById(token: string, domainName: string, userId: string): Promise<TenantUserResponse>;
35
+ declare function batchGetUsers(token: string, domainName: string, userIds: string[]): Promise<BatchUsersResponse>;
36
+
3
37
  interface CacheOptions {
4
38
  ttlMs: number;
5
39
  }
@@ -39,6 +73,7 @@ interface IDauthUser {
39
73
  }
40
74
  interface IRequestDauth extends Request {
41
75
  user: IDauthUser;
76
+ dauthToken: string;
42
77
  files: {
43
78
  image: {
44
79
  path: string;
@@ -68,6 +103,6 @@ interface TCustomResponse extends Response {
68
103
  send(body?: unknown): this;
69
104
  }
70
105
 
71
- declare const dauth: ({ domainName, tsk, cache, session, }: DauthOptions) => (req: IRequestDauth, res: TCustomResponse, next: NextFunction) => Promise<void | TCustomResponse>;
106
+ declare const dauth: ({ domainName, tsk, cache, session }: DauthOptions) => (req: IRequestDauth, res: TCustomResponse, next: NextFunction) => Promise<void | TCustomResponse>;
72
107
 
73
- export { type AuthMethodType, type CacheOptions, type DauthOptions, type IDauthUser, type IRequestDauth, type SessionOptions, UserCache, dauth };
108
+ export { type AuthMethodType, type CacheOptions, type DauthOptions, type IDauthUser, type IRequestDauth, type SessionOptions, type TenantUser, UserCache, batchGetUsers, dauth, getUserById, searchUserByEmail };
package/dist/index.js CHANGED
@@ -31,7 +31,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
33
  UserCache: () => UserCache,
34
- dauth: () => dauth
34
+ batchGetUsers: () => batchGetUsers,
35
+ dauth: () => dauth,
36
+ getUserById: () => getUserById,
37
+ searchUserByEmail: () => searchUserByEmail
35
38
  });
36
39
  module.exports = __toCommonJS(index_exports);
37
40
  var import_jsonwebtoken = __toESM(require("jsonwebtoken"));
@@ -66,6 +69,50 @@ async function getUser(token, domainName) {
66
69
  const data = await response.json();
67
70
  return { response: { status: response.status }, data };
68
71
  }
72
+ async function searchUserByEmail(token, domainName, email) {
73
+ const params = new URLSearchParams({ email });
74
+ const response = await fetch(
75
+ `${getServerBasePath()}/app/${domainName}/users/search?${params}`,
76
+ {
77
+ method: "GET",
78
+ headers: {
79
+ Authorization: token,
80
+ "Content-Type": "application/json"
81
+ }
82
+ }
83
+ );
84
+ const data = await response.json();
85
+ return { response: { status: response.status }, data };
86
+ }
87
+ async function getUserById(token, domainName, userId) {
88
+ const response = await fetch(
89
+ `${getServerBasePath()}/app/${domainName}/users/${userId}`,
90
+ {
91
+ method: "GET",
92
+ headers: {
93
+ Authorization: token,
94
+ "Content-Type": "application/json"
95
+ }
96
+ }
97
+ );
98
+ const data = await response.json();
99
+ return { response: { status: response.status }, data };
100
+ }
101
+ async function batchGetUsers(token, domainName, userIds) {
102
+ const response = await fetch(
103
+ `${getServerBasePath()}/app/${domainName}/users/batch`,
104
+ {
105
+ method: "POST",
106
+ headers: {
107
+ Authorization: token,
108
+ "Content-Type": "application/json"
109
+ },
110
+ body: JSON.stringify({ userIds })
111
+ }
112
+ );
113
+ const data = await response.json();
114
+ return { response: { status: response.status }, data };
115
+ }
69
116
 
70
117
  // src/cache.ts
71
118
  var UserCache = class {
@@ -152,27 +199,17 @@ function decryptSessionWithKeys(ciphertext, keys) {
152
199
  }
153
200
 
154
201
  // src/index.ts
155
- var dauth = ({
156
- domainName,
157
- tsk,
158
- cache,
159
- session
160
- }) => {
202
+ var dauth = ({ domainName, tsk, cache, session }) => {
161
203
  const userCache = cache ? new UserCache(cache) : null;
162
204
  let keysPromise = null;
163
205
  async function getEncKeys() {
164
206
  if (!keysPromise) {
165
207
  keysPromise = (async () => {
166
208
  const keys = [];
167
- keys.push(
168
- await deriveEncryptionKey(tsk, session?.sessionSalt)
169
- );
209
+ keys.push(await deriveEncryptionKey(tsk, session?.sessionSalt));
170
210
  if (session?.previousTsk) {
171
211
  keys.push(
172
- await deriveEncryptionKey(
173
- session.previousTsk,
174
- session.sessionSalt
175
- )
212
+ await deriveEncryptionKey(session.previousTsk, session.sessionSalt)
176
213
  );
177
214
  }
178
215
  return keys;
@@ -229,6 +266,7 @@ var dauth = ({
229
266
  }
230
267
  return res.status(401).send({ status: "token-invalid", message });
231
268
  }
269
+ req.dauthToken = token;
232
270
  if (userCache) {
233
271
  const cachedUser = userCache.get(token);
234
272
  if (cachedUser) {
@@ -270,6 +308,9 @@ var dauth = ({
270
308
  // Annotate the CommonJS export names for ESM import in node:
271
309
  0 && (module.exports = {
272
310
  UserCache,
273
- dauth
311
+ batchGetUsers,
312
+ dauth,
313
+ getUserById,
314
+ searchUserByEmail
274
315
  });
275
316
  //# sourceMappingURL=index.js.map