dauth-md-node 1.0.1 → 2.1.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,6 +1,6 @@
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 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`.
4
4
 
5
5
  ## Installation
6
6
 
@@ -40,14 +40,14 @@ Factory function that returns an Express middleware.
40
40
 
41
41
  | Parameter | Type | Description |
42
42
  |---|---|---|
43
- | `domainName` | `string` | Your DAuth domain name (used for API routing) |
43
+ | `domainName` | `string` | Your Dauth domain name (used for API routing) |
44
44
  | `tsk` | `string` | Tenant Secret Key for local JWT verification |
45
45
 
46
46
  ### Middleware Behavior
47
47
 
48
48
  1. Extracts the `Authorization` header from the request
49
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 /tenant/:domainName/user`)
50
+ 3. Fetches the full user object from the Dauth backend (`GET /app/:domainName/user`)
51
51
  4. Attaches the user to `req.user`
52
52
  5. Calls `next()` on success
53
53
 
@@ -58,8 +58,8 @@ Factory function that returns an Express middleware.
58
58
  | Missing `Authorization` header | 403 | `token-not-found` |
59
59
  | JWT expired | 401 | `token-expired` |
60
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` |
61
+ | User not found in Dauth backend | 404 | `user-not-found` |
62
+ | Dauth backend server error | 500 | `error` |
63
63
  | Other backend status | 501 | `request-error` |
64
64
 
65
65
  ### `req.user` Object
@@ -89,7 +89,7 @@ Both `IDauthUser` and `IRequestDauth` are exported from the package for type-saf
89
89
 
90
90
  ## Real-World Integration Example
91
91
 
92
- This is the pattern used in `easymediacloud-backend-node`, which delegates all user authentication to dauth.
92
+ This is the pattern used in `easymediacloud-backend-node`, which delegates all user authentication to Dauth.
93
93
 
94
94
  ### 1. Initialize the middleware from environment variables
95
95
 
@@ -169,17 +169,17 @@ export const getMyLicenses = async (req: IRequestDauth, res: Response) => {
169
169
  ## Environment Detection
170
170
 
171
171
  - **Development** (`NODE_ENV=development`): Routes API calls to `http://localhost:4012/api/v1`
172
- - **Production**: Routes API calls to `https://<domainName>.dauth.ovh/api/v1`
172
+ - **Production**: Routes API calls to `https://dauth.ovh/api/v1`
173
173
 
174
174
  ## Development
175
175
 
176
176
  ```bash
177
- npm start # Watch mode (tsdx watch)
178
- npm run build # Production build (CJS + ESM)
179
- npm test # Run Jest tests
180
- npm run lint # ESLint via tsdx
181
- npm run size # Check bundle size (10KB budget per entry)
182
- npm run analyze # Bundle size analysis with visualization
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
183
183
  ```
184
184
 
185
185
  ### Bundle Outputs
@@ -0,0 +1,66 @@
1
+ import { Request, Response, NextFunction } from 'express';
2
+
3
+ interface CacheOptions {
4
+ ttlMs: number;
5
+ }
6
+ declare class UserCache {
7
+ private store;
8
+ private ttlMs;
9
+ constructor(options: CacheOptions);
10
+ get(token: string): IDauthUser | undefined;
11
+ set(token: string, user: IDauthUser): void;
12
+ clear(): void;
13
+ private sweep;
14
+ }
15
+
16
+ type AuthMethodType = 'password' | 'magic-link' | 'passkey';
17
+ interface IDauthUser {
18
+ _id: string;
19
+ name: string;
20
+ lastname: string;
21
+ nickname: string;
22
+ email: string;
23
+ isVerified: boolean;
24
+ language: string;
25
+ avatar: {
26
+ id: string;
27
+ url: string;
28
+ };
29
+ role: string;
30
+ telPrefix: string;
31
+ telSuffix: string;
32
+ birthDate?: string;
33
+ country?: string;
34
+ metadata?: Record<string, unknown>;
35
+ authMethods?: AuthMethodType[];
36
+ createdAt: Date;
37
+ updatedAt: Date;
38
+ lastLogin: Date;
39
+ }
40
+ interface IRequestDauth extends Request {
41
+ user: IDauthUser;
42
+ files: {
43
+ image: {
44
+ path: string;
45
+ };
46
+ avatar: {
47
+ path: string;
48
+ };
49
+ };
50
+ headers: {
51
+ authorization: string;
52
+ };
53
+ }
54
+ interface DauthOptions {
55
+ domainName: string;
56
+ tsk: string;
57
+ cache?: CacheOptions;
58
+ }
59
+ interface TCustomResponse extends Response {
60
+ status(code: number): this;
61
+ send(body?: unknown): this;
62
+ }
63
+
64
+ declare const dauth: ({ domainName, tsk, cache }: DauthOptions) => (req: IRequestDauth, res: TCustomResponse, next: NextFunction) => Promise<void | TCustomResponse>;
65
+
66
+ export { type AuthMethodType, type CacheOptions, type DauthOptions, type IDauthUser, type IRequestDauth, UserCache, dauth };
package/dist/index.d.ts CHANGED
@@ -1,43 +1,66 @@
1
- import { Request, NextFunction, Response as ExpressResponse, Handler } from 'express';
2
- export interface IDauthUser {
3
- _id: string;
4
- name: string;
5
- lastname: string;
6
- nickname: string;
7
- email: string;
8
- isVerified: boolean;
9
- language: string;
10
- avatar: {
11
- id: string;
12
- url: string;
13
- };
14
- role: string;
15
- telPrefix: string;
16
- telSuffix: string;
17
- createdAt: Date;
18
- updatedAt: Date;
19
- lastLogin: Date;
20
- }
21
- export interface IRequestDauth extends Request {
22
- user: IDauthUser;
23
- files: {
24
- image: {
25
- path: string;
26
- };
27
- avatar: {
28
- path: string;
29
- };
30
- };
31
- headers: {
32
- authorization: string;
33
- };
34
- }
35
- interface TCustomResponse extends ExpressResponse {
36
- status(code: number): any;
37
- send(body?: any): any;
38
- }
39
- export declare const dauth: ({ domainName, tsk, }: {
40
- domainName: string;
41
- tsk: string;
42
- }) => (req: IRequestDauth, res: TCustomResponse, next: NextFunction) => Handler | void;
43
- export {};
1
+ import { Request, Response, NextFunction } from 'express';
2
+
3
+ interface CacheOptions {
4
+ ttlMs: number;
5
+ }
6
+ declare class UserCache {
7
+ private store;
8
+ private ttlMs;
9
+ constructor(options: CacheOptions);
10
+ get(token: string): IDauthUser | undefined;
11
+ set(token: string, user: IDauthUser): void;
12
+ clear(): void;
13
+ private sweep;
14
+ }
15
+
16
+ type AuthMethodType = 'password' | 'magic-link' | 'passkey';
17
+ interface IDauthUser {
18
+ _id: string;
19
+ name: string;
20
+ lastname: string;
21
+ nickname: string;
22
+ email: string;
23
+ isVerified: boolean;
24
+ language: string;
25
+ avatar: {
26
+ id: string;
27
+ url: string;
28
+ };
29
+ role: string;
30
+ telPrefix: string;
31
+ telSuffix: string;
32
+ birthDate?: string;
33
+ country?: string;
34
+ metadata?: Record<string, unknown>;
35
+ authMethods?: AuthMethodType[];
36
+ createdAt: Date;
37
+ updatedAt: Date;
38
+ lastLogin: Date;
39
+ }
40
+ interface IRequestDauth extends Request {
41
+ user: IDauthUser;
42
+ files: {
43
+ image: {
44
+ path: string;
45
+ };
46
+ avatar: {
47
+ path: string;
48
+ };
49
+ };
50
+ headers: {
51
+ authorization: string;
52
+ };
53
+ }
54
+ interface DauthOptions {
55
+ domainName: string;
56
+ tsk: string;
57
+ cache?: CacheOptions;
58
+ }
59
+ interface TCustomResponse extends Response {
60
+ status(code: number): this;
61
+ send(body?: unknown): this;
62
+ }
63
+
64
+ declare const dauth: ({ domainName, tsk, cache }: DauthOptions) => (req: IRequestDauth, res: TCustomResponse, next: NextFunction) => Promise<void | TCustomResponse>;
65
+
66
+ export { type AuthMethodType, type CacheOptions, type DauthOptions, type IDauthUser, type IRequestDauth, UserCache, dauth };
package/dist/index.js CHANGED
@@ -1,8 +1,171 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
1
29
 
2
- 'use strict'
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ UserCache: () => UserCache,
34
+ dauth: () => dauth
35
+ });
36
+ module.exports = __toCommonJS(index_exports);
37
+ var import_jsonwebtoken = __toESM(require("jsonwebtoken"));
3
38
 
4
- if (process.env.NODE_ENV === 'production') {
5
- module.exports = require('./dauth-md-node.cjs.production.min.js')
6
- } else {
7
- module.exports = require('./dauth-md-node.cjs.development.js')
39
+ // src/api/utils/config.ts
40
+ var apiVersion = "v1";
41
+ var serverDomain = "dauth.ovh";
42
+ function getServerBasePath() {
43
+ if (process.env.DAUTH_URL) {
44
+ const base = process.env.DAUTH_URL.replace(/\/+$/, "");
45
+ return `${base}/api/${apiVersion}`;
46
+ }
47
+ const isLocalhost = process.env.NODE_ENV === "development";
48
+ const serverPort = 4012;
49
+ const serverLocalUrl = `http://localhost:${serverPort}/api/${apiVersion}`;
50
+ const serverProdUrl = `https://${serverDomain}/api/${apiVersion}`;
51
+ return isLocalhost ? serverLocalUrl : serverProdUrl;
8
52
  }
53
+
54
+ // src/api/dauth.api.ts
55
+ async function getUser(token, domainName) {
56
+ const response = await fetch(
57
+ `${getServerBasePath()}/app/${domainName}/user`,
58
+ {
59
+ method: "GET",
60
+ headers: {
61
+ Authorization: token,
62
+ "Content-Type": "application/json"
63
+ }
64
+ }
65
+ );
66
+ const data = await response.json();
67
+ return { response: { status: response.status }, data };
68
+ }
69
+
70
+ // src/cache.ts
71
+ var UserCache = class {
72
+ store = /* @__PURE__ */ new Map();
73
+ ttlMs;
74
+ constructor(options) {
75
+ this.ttlMs = options.ttlMs;
76
+ }
77
+ get(token) {
78
+ const entry = this.store.get(token);
79
+ if (!entry) return void 0;
80
+ if (Date.now() > entry.expiresAt) {
81
+ this.store.delete(token);
82
+ return void 0;
83
+ }
84
+ return entry.user;
85
+ }
86
+ set(token, user) {
87
+ if (this.store.size > 1e3) {
88
+ this.sweep();
89
+ }
90
+ this.store.set(token, { user, expiresAt: Date.now() + this.ttlMs });
91
+ }
92
+ clear() {
93
+ this.store.clear();
94
+ }
95
+ sweep() {
96
+ const now = Date.now();
97
+ for (const [key, entry] of this.store) {
98
+ if (now > entry.expiresAt) {
99
+ this.store.delete(key);
100
+ }
101
+ }
102
+ }
103
+ };
104
+
105
+ // src/index.ts
106
+ var dauth = ({ domainName, tsk, cache }) => {
107
+ const userCache = cache ? new UserCache(cache) : null;
108
+ return async (req, res, next) => {
109
+ if (!req.headers.authorization) {
110
+ return res.status(403).send({ status: "token-not-found", message: "Token not found" });
111
+ }
112
+ const token = req.headers.authorization.replace(/['"]+/g, "");
113
+ try {
114
+ import_jsonwebtoken.default.verify(token, tsk);
115
+ } catch (error) {
116
+ const message = error instanceof Error ? error.message : "Token invalid";
117
+ if (message === "jwt expired") {
118
+ return res.status(401).send({ status: "token-expired", message: "jwt expired" });
119
+ }
120
+ if (message === "invalid signature") {
121
+ return res.status(401).send({
122
+ status: "tsk-not-invalid",
123
+ message: "The TSK variable in the backend middleware is not valid"
124
+ });
125
+ }
126
+ return res.status(401).send({ status: "token-invalid", message });
127
+ }
128
+ if (userCache) {
129
+ const cachedUser = userCache.get(token);
130
+ if (cachedUser) {
131
+ req.user = cachedUser;
132
+ return next();
133
+ }
134
+ }
135
+ try {
136
+ const getUserFetch = await getUser(token, domainName);
137
+ if (getUserFetch.response.status === 404) {
138
+ return res.status(404).send({
139
+ status: "user-not-found",
140
+ message: getUserFetch.data.message ?? "User does not exist"
141
+ });
142
+ }
143
+ if (getUserFetch.response.status === 500) {
144
+ return res.status(500).send({
145
+ status: "error",
146
+ message: getUserFetch.data.message ?? "Dauth server error"
147
+ });
148
+ }
149
+ if (getUserFetch.response.status === 200) {
150
+ req.user = getUserFetch.data.user;
151
+ if (userCache) {
152
+ userCache.set(token, req.user);
153
+ }
154
+ return next();
155
+ }
156
+ return res.status(501).send({
157
+ status: "request-error",
158
+ message: getUserFetch.data.message ?? "Dauth server error"
159
+ });
160
+ } catch (error) {
161
+ const message = error instanceof Error ? error.message : "Dauth server error";
162
+ return res.status(500).send({ status: "server-error", message });
163
+ }
164
+ };
165
+ };
166
+ // Annotate the CommonJS export names for ESM import in node:
167
+ 0 && (module.exports = {
168
+ UserCache,
169
+ dauth
170
+ });
171
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/api/utils/config.ts","../src/api/dauth.api.ts","../src/cache.ts"],"sourcesContent":["import { Request, NextFunction, Response as ExpressResponse } from 'express';\nimport jwt from 'jsonwebtoken';\nimport { getUser } from './api/dauth.api';\nimport { UserCache } from './cache';\nimport type { CacheOptions } from './cache';\n\nexport type AuthMethodType = 'password' | 'magic-link' | 'passkey';\n\nexport interface IDauthUser {\n _id: string;\n name: string;\n lastname: string;\n nickname: string;\n email: string;\n isVerified: boolean;\n language: string;\n avatar: {\n id: string;\n url: string;\n };\n role: string;\n telPrefix: string;\n telSuffix: string;\n birthDate?: string;\n country?: string;\n metadata?: Record<string, unknown>;\n authMethods?: AuthMethodType[];\n createdAt: Date;\n updatedAt: Date;\n lastLogin: Date;\n}\n\nexport interface IRequestDauth extends Request {\n user: IDauthUser;\n files: {\n image: { path: string };\n avatar: { path: string };\n };\n headers: {\n authorization: string;\n };\n}\n\nexport interface DauthOptions {\n domainName: string;\n tsk: string;\n cache?: CacheOptions;\n}\n\ninterface TCustomResponse extends ExpressResponse {\n status(code: number): this;\n send(body?: unknown): this;\n}\n\nexport { UserCache };\nexport type { CacheOptions };\n\nexport const dauth = ({ domainName, tsk, cache }: DauthOptions) => {\n const userCache = cache ? new UserCache(cache) : null;\n\n return async (\n req: IRequestDauth,\n res: TCustomResponse,\n next: NextFunction\n ) => {\n if (!req.headers.authorization) {\n return res\n .status(403)\n .send({ status: 'token-not-found', message: 'Token not found' });\n }\n\n const token = req.headers.authorization.replace(/['\"]+/g, '');\n\n try {\n jwt.verify(token, tsk);\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Token invalid';\n\n if (message === 'jwt expired') {\n return res\n .status(401)\n .send({ status: 'token-expired', message: 'jwt expired' });\n }\n if (message === 'invalid signature') {\n return res.status(401).send({\n status: 'tsk-not-invalid',\n message:\n 'The TSK variable in the backend middleware is not valid',\n });\n }\n return res\n .status(401)\n .send({ status: 'token-invalid', message });\n }\n\n if (userCache) {\n const cachedUser = userCache.get(token);\n if (cachedUser) {\n req.user = cachedUser;\n return next();\n }\n }\n\n try {\n const getUserFetch = await getUser(token, domainName);\n\n if (getUserFetch.response.status === 404) {\n return res.status(404).send({\n status: 'user-not-found',\n message: getUserFetch.data.message ?? 'User does not exist',\n });\n }\n if (getUserFetch.response.status === 500) {\n return res.status(500).send({\n status: 'error',\n message: getUserFetch.data.message ?? 'Dauth server error',\n });\n }\n if (getUserFetch.response.status === 200) {\n req.user = getUserFetch.data.user;\n if (userCache) {\n userCache.set(token, req.user);\n }\n return next();\n }\n return res.status(501).send({\n status: 'request-error',\n message: getUserFetch.data.message ?? 'Dauth server error',\n });\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Dauth server error';\n return res\n .status(500)\n .send({ status: 'server-error', message });\n }\n };\n};\n","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 { getServerBasePath } from './utils/config';\n\ninterface GetUserResponse {\n response: { status: number };\n data: { user?: any; message?: string };\n}\n\nexport async function getUser(\n token: string,\n domainName: string\n): Promise<GetUserResponse> {\n const response = await fetch(\n `${getServerBasePath()}/app/${domainName}/user`,\n {\n method: 'GET',\n headers: {\n Authorization: token,\n 'Content-Type': 'application/json',\n },\n }\n );\n const data = (await response.json()) as GetUserResponse['data'];\n return { response: { status: response.status }, data };\n}\n","import { IDauthUser } from './index';\n\ninterface CacheEntry {\n user: IDauthUser;\n expiresAt: number;\n}\n\nexport interface CacheOptions {\n ttlMs: number;\n}\n\nexport class UserCache {\n private store = new Map<string, CacheEntry>();\n private ttlMs: number;\n\n constructor(options: CacheOptions) {\n this.ttlMs = options.ttlMs;\n }\n\n get(token: string): IDauthUser | undefined {\n const entry = this.store.get(token);\n if (!entry) return undefined;\n\n if (Date.now() > entry.expiresAt) {\n this.store.delete(token);\n return undefined;\n }\n\n return entry.user;\n }\n\n set(token: string, user: IDauthUser): void {\n if (this.store.size > 1000) {\n this.sweep();\n }\n this.store.set(token, { user, expiresAt: Date.now() + this.ttlMs });\n }\n\n clear(): void {\n this.store.clear();\n }\n\n private sweep(): void {\n const now = Date.now();\n for (const [key, entry] of this.store) {\n if (now > entry.expiresAt) {\n this.store.delete(key);\n }\n }\n }\n}\n"],"mappings":"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","names":["jwt"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,135 @@
1
+ // src/index.ts
2
+ import jwt from "jsonwebtoken";
3
+
4
+ // src/api/utils/config.ts
5
+ var apiVersion = "v1";
6
+ var serverDomain = "dauth.ovh";
7
+ function getServerBasePath() {
8
+ if (process.env.DAUTH_URL) {
9
+ const base = process.env.DAUTH_URL.replace(/\/+$/, "");
10
+ return `${base}/api/${apiVersion}`;
11
+ }
12
+ const isLocalhost = process.env.NODE_ENV === "development";
13
+ const serverPort = 4012;
14
+ const serverLocalUrl = `http://localhost:${serverPort}/api/${apiVersion}`;
15
+ const serverProdUrl = `https://${serverDomain}/api/${apiVersion}`;
16
+ return isLocalhost ? serverLocalUrl : serverProdUrl;
17
+ }
18
+
19
+ // src/api/dauth.api.ts
20
+ async function getUser(token, domainName) {
21
+ const response = await fetch(
22
+ `${getServerBasePath()}/app/${domainName}/user`,
23
+ {
24
+ method: "GET",
25
+ headers: {
26
+ Authorization: token,
27
+ "Content-Type": "application/json"
28
+ }
29
+ }
30
+ );
31
+ const data = await response.json();
32
+ return { response: { status: response.status }, data };
33
+ }
34
+
35
+ // src/cache.ts
36
+ var UserCache = class {
37
+ store = /* @__PURE__ */ new Map();
38
+ ttlMs;
39
+ constructor(options) {
40
+ this.ttlMs = options.ttlMs;
41
+ }
42
+ get(token) {
43
+ const entry = this.store.get(token);
44
+ if (!entry) return void 0;
45
+ if (Date.now() > entry.expiresAt) {
46
+ this.store.delete(token);
47
+ return void 0;
48
+ }
49
+ return entry.user;
50
+ }
51
+ set(token, user) {
52
+ if (this.store.size > 1e3) {
53
+ this.sweep();
54
+ }
55
+ this.store.set(token, { user, expiresAt: Date.now() + this.ttlMs });
56
+ }
57
+ clear() {
58
+ this.store.clear();
59
+ }
60
+ sweep() {
61
+ const now = Date.now();
62
+ for (const [key, entry] of this.store) {
63
+ if (now > entry.expiresAt) {
64
+ this.store.delete(key);
65
+ }
66
+ }
67
+ }
68
+ };
69
+
70
+ // src/index.ts
71
+ var dauth = ({ domainName, tsk, cache }) => {
72
+ const userCache = cache ? new UserCache(cache) : null;
73
+ return async (req, res, next) => {
74
+ if (!req.headers.authorization) {
75
+ return res.status(403).send({ status: "token-not-found", message: "Token not found" });
76
+ }
77
+ const token = req.headers.authorization.replace(/['"]+/g, "");
78
+ try {
79
+ jwt.verify(token, tsk);
80
+ } catch (error) {
81
+ const message = error instanceof Error ? error.message : "Token invalid";
82
+ if (message === "jwt expired") {
83
+ return res.status(401).send({ status: "token-expired", message: "jwt expired" });
84
+ }
85
+ if (message === "invalid signature") {
86
+ return res.status(401).send({
87
+ status: "tsk-not-invalid",
88
+ message: "The TSK variable in the backend middleware is not valid"
89
+ });
90
+ }
91
+ return res.status(401).send({ status: "token-invalid", message });
92
+ }
93
+ if (userCache) {
94
+ const cachedUser = userCache.get(token);
95
+ if (cachedUser) {
96
+ req.user = cachedUser;
97
+ return next();
98
+ }
99
+ }
100
+ try {
101
+ const getUserFetch = await getUser(token, domainName);
102
+ if (getUserFetch.response.status === 404) {
103
+ return res.status(404).send({
104
+ status: "user-not-found",
105
+ message: getUserFetch.data.message ?? "User does not exist"
106
+ });
107
+ }
108
+ if (getUserFetch.response.status === 500) {
109
+ return res.status(500).send({
110
+ status: "error",
111
+ message: getUserFetch.data.message ?? "Dauth server error"
112
+ });
113
+ }
114
+ if (getUserFetch.response.status === 200) {
115
+ req.user = getUserFetch.data.user;
116
+ if (userCache) {
117
+ userCache.set(token, req.user);
118
+ }
119
+ return next();
120
+ }
121
+ return res.status(501).send({
122
+ status: "request-error",
123
+ message: getUserFetch.data.message ?? "Dauth server error"
124
+ });
125
+ } catch (error) {
126
+ const message = error instanceof Error ? error.message : "Dauth server error";
127
+ return res.status(500).send({ status: "server-error", message });
128
+ }
129
+ };
130
+ };
131
+ export {
132
+ UserCache,
133
+ dauth
134
+ };
135
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/api/utils/config.ts","../src/api/dauth.api.ts","../src/cache.ts"],"sourcesContent":["import { Request, NextFunction, Response as ExpressResponse } from 'express';\nimport jwt from 'jsonwebtoken';\nimport { getUser } from './api/dauth.api';\nimport { UserCache } from './cache';\nimport type { CacheOptions } from './cache';\n\nexport type AuthMethodType = 'password' | 'magic-link' | 'passkey';\n\nexport interface IDauthUser {\n _id: string;\n name: string;\n lastname: string;\n nickname: string;\n email: string;\n isVerified: boolean;\n language: string;\n avatar: {\n id: string;\n url: string;\n };\n role: string;\n telPrefix: string;\n telSuffix: string;\n birthDate?: string;\n country?: string;\n metadata?: Record<string, unknown>;\n authMethods?: AuthMethodType[];\n createdAt: Date;\n updatedAt: Date;\n lastLogin: Date;\n}\n\nexport interface IRequestDauth extends Request {\n user: IDauthUser;\n files: {\n image: { path: string };\n avatar: { path: string };\n };\n headers: {\n authorization: string;\n };\n}\n\nexport interface DauthOptions {\n domainName: string;\n tsk: string;\n cache?: CacheOptions;\n}\n\ninterface TCustomResponse extends ExpressResponse {\n status(code: number): this;\n send(body?: unknown): this;\n}\n\nexport { UserCache };\nexport type { CacheOptions };\n\nexport const dauth = ({ domainName, tsk, cache }: DauthOptions) => {\n const userCache = cache ? new UserCache(cache) : null;\n\n return async (\n req: IRequestDauth,\n res: TCustomResponse,\n next: NextFunction\n ) => {\n if (!req.headers.authorization) {\n return res\n .status(403)\n .send({ status: 'token-not-found', message: 'Token not found' });\n }\n\n const token = req.headers.authorization.replace(/['\"]+/g, '');\n\n try {\n jwt.verify(token, tsk);\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Token invalid';\n\n if (message === 'jwt expired') {\n return res\n .status(401)\n .send({ status: 'token-expired', message: 'jwt expired' });\n }\n if (message === 'invalid signature') {\n return res.status(401).send({\n status: 'tsk-not-invalid',\n message:\n 'The TSK variable in the backend middleware is not valid',\n });\n }\n return res\n .status(401)\n .send({ status: 'token-invalid', message });\n }\n\n if (userCache) {\n const cachedUser = userCache.get(token);\n if (cachedUser) {\n req.user = cachedUser;\n return next();\n }\n }\n\n try {\n const getUserFetch = await getUser(token, domainName);\n\n if (getUserFetch.response.status === 404) {\n return res.status(404).send({\n status: 'user-not-found',\n message: getUserFetch.data.message ?? 'User does not exist',\n });\n }\n if (getUserFetch.response.status === 500) {\n return res.status(500).send({\n status: 'error',\n message: getUserFetch.data.message ?? 'Dauth server error',\n });\n }\n if (getUserFetch.response.status === 200) {\n req.user = getUserFetch.data.user;\n if (userCache) {\n userCache.set(token, req.user);\n }\n return next();\n }\n return res.status(501).send({\n status: 'request-error',\n message: getUserFetch.data.message ?? 'Dauth server error',\n });\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Dauth server error';\n return res\n .status(500)\n .send({ status: 'server-error', message });\n }\n };\n};\n","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 { getServerBasePath } from './utils/config';\n\ninterface GetUserResponse {\n response: { status: number };\n data: { user?: any; message?: string };\n}\n\nexport async function getUser(\n token: string,\n domainName: string\n): Promise<GetUserResponse> {\n const response = await fetch(\n `${getServerBasePath()}/app/${domainName}/user`,\n {\n method: 'GET',\n headers: {\n Authorization: token,\n 'Content-Type': 'application/json',\n },\n }\n );\n const data = (await response.json()) as GetUserResponse['data'];\n return { response: { status: response.status }, data };\n}\n","import { IDauthUser } from './index';\n\ninterface CacheEntry {\n user: IDauthUser;\n expiresAt: number;\n}\n\nexport interface CacheOptions {\n ttlMs: number;\n}\n\nexport class UserCache {\n private store = new Map<string, CacheEntry>();\n private ttlMs: number;\n\n constructor(options: CacheOptions) {\n this.ttlMs = options.ttlMs;\n }\n\n get(token: string): IDauthUser | undefined {\n const entry = this.store.get(token);\n if (!entry) return undefined;\n\n if (Date.now() > entry.expiresAt) {\n this.store.delete(token);\n return undefined;\n }\n\n return entry.user;\n }\n\n set(token: string, user: IDauthUser): void {\n if (this.store.size > 1000) {\n this.sweep();\n }\n this.store.set(token, { user, expiresAt: Date.now() + this.ttlMs });\n }\n\n clear(): void {\n this.store.clear();\n }\n\n private sweep(): void {\n const now = Date.now();\n for (const [key, entry] of this.store) {\n if (now > entry.expiresAt) {\n this.store.delete(key);\n }\n }\n }\n}\n"],"mappings":"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","names":[]}