@pedr0ni/nestjs-better-auth 1.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/LICENSE +7 -0
- package/README.md +429 -0
- package/dist/index.cjs +535 -0
- package/dist/index.d.cts +232 -0
- package/dist/index.d.mts +232 -0
- package/dist/index.d.ts +232 -0
- package/dist/index.mjs +506 -0
- package/package.json +80 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,535 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const common = require('@nestjs/common');
|
|
4
|
+
const core = require('@nestjs/core');
|
|
5
|
+
const node = require('better-auth/node');
|
|
6
|
+
const plugins = require('better-auth/plugins');
|
|
7
|
+
const express = require('express');
|
|
8
|
+
const shared_utils_js = require('@nestjs/common/utils/shared.utils.js');
|
|
9
|
+
const utils_js = require('@nestjs/core/middleware/utils.js');
|
|
10
|
+
|
|
11
|
+
function _interopNamespaceCompat(e) {
|
|
12
|
+
if (e && typeof e === 'object' && 'default' in e) return e;
|
|
13
|
+
const n = Object.create(null);
|
|
14
|
+
if (e) {
|
|
15
|
+
for (const k in e) {
|
|
16
|
+
n[k] = e[k];
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
n.default = e;
|
|
20
|
+
return n;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const express__namespace = /*#__PURE__*/_interopNamespaceCompat(express);
|
|
24
|
+
|
|
25
|
+
const BEFORE_HOOK_KEY = Symbol("BEFORE_HOOK");
|
|
26
|
+
const AFTER_HOOK_KEY = Symbol("AFTER_HOOK");
|
|
27
|
+
const HOOK_KEY = Symbol("HOOK");
|
|
28
|
+
const AUTH_MODULE_OPTIONS_KEY = Symbol("AUTH_MODULE_OPTIONS");
|
|
29
|
+
|
|
30
|
+
let GqlExecutionContext;
|
|
31
|
+
function getGqlExecutionContext() {
|
|
32
|
+
if (!GqlExecutionContext) {
|
|
33
|
+
GqlExecutionContext = require("@nestjs/graphql").GqlExecutionContext;
|
|
34
|
+
}
|
|
35
|
+
return GqlExecutionContext;
|
|
36
|
+
}
|
|
37
|
+
function getRequestFromContext(context) {
|
|
38
|
+
const contextType = context.getType();
|
|
39
|
+
if (contextType === "graphql") {
|
|
40
|
+
return getGqlExecutionContext().create(context).getContext().req;
|
|
41
|
+
}
|
|
42
|
+
if (contextType === "ws") {
|
|
43
|
+
return context.switchToWs().getClient();
|
|
44
|
+
}
|
|
45
|
+
return context.switchToHttp().getRequest();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const AllowAnonymous = () => common.SetMetadata("PUBLIC", true);
|
|
49
|
+
const OptionalAuth = () => common.SetMetadata("OPTIONAL", true);
|
|
50
|
+
const Roles = (roles) => common.SetMetadata("ROLES", roles);
|
|
51
|
+
const OrgRoles = (roles) => common.SetMetadata("ORG_ROLES", roles);
|
|
52
|
+
const Public = AllowAnonymous;
|
|
53
|
+
const Optional = OptionalAuth;
|
|
54
|
+
const Session = common.createParamDecorator((_data, context) => {
|
|
55
|
+
const request = getRequestFromContext(context);
|
|
56
|
+
return request.session;
|
|
57
|
+
});
|
|
58
|
+
const BeforeHook = (path) => common.SetMetadata(BEFORE_HOOK_KEY, path);
|
|
59
|
+
const AfterHook = (path) => common.SetMetadata(AFTER_HOOK_KEY, path);
|
|
60
|
+
const Hook = () => common.SetMetadata(HOOK_KEY, true);
|
|
61
|
+
|
|
62
|
+
const MODULE_OPTIONS_TOKEN = Symbol("AUTH_MODULE_OPTIONS");
|
|
63
|
+
const { ConfigurableModuleClass, OPTIONS_TYPE, ASYNC_OPTIONS_TYPE } = new common.ConfigurableModuleBuilder({
|
|
64
|
+
optionsInjectionToken: MODULE_OPTIONS_TOKEN
|
|
65
|
+
}).setClassMethodName("forRoot").setExtras(
|
|
66
|
+
{
|
|
67
|
+
isGlobal: true,
|
|
68
|
+
disableGlobalAuthGuard: false,
|
|
69
|
+
disableControllers: false
|
|
70
|
+
},
|
|
71
|
+
(def, extras) => {
|
|
72
|
+
return {
|
|
73
|
+
...def,
|
|
74
|
+
exports: [MODULE_OPTIONS_TOKEN],
|
|
75
|
+
global: extras.isGlobal
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
).build();
|
|
79
|
+
|
|
80
|
+
var __getOwnPropDesc$2 = Object.getOwnPropertyDescriptor;
|
|
81
|
+
var __decorateClass$2 = (decorators, target, key, kind) => {
|
|
82
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$2(target, key) : target;
|
|
83
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
84
|
+
if (decorator = decorators[i])
|
|
85
|
+
result = (decorator(result)) || result;
|
|
86
|
+
return result;
|
|
87
|
+
};
|
|
88
|
+
var __decorateParam$2 = (index, decorator) => (target, key) => decorator(target, key, index);
|
|
89
|
+
exports.AuthService = class AuthService {
|
|
90
|
+
constructor(options) {
|
|
91
|
+
this.options = options;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Returns the API endpoints provided by the auth instance
|
|
95
|
+
*/
|
|
96
|
+
get api() {
|
|
97
|
+
return this.options.auth.api;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Returns the complete auth instance
|
|
101
|
+
* Access this for plugin-specific functionality
|
|
102
|
+
*/
|
|
103
|
+
get instance() {
|
|
104
|
+
return this.options.auth;
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
exports.AuthService = __decorateClass$2([
|
|
108
|
+
__decorateParam$2(0, common.Inject(MODULE_OPTIONS_TOKEN))
|
|
109
|
+
], exports.AuthService);
|
|
110
|
+
|
|
111
|
+
var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
|
|
112
|
+
var __decorateClass$1 = (decorators, target, key, kind) => {
|
|
113
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$1(target, key) : target;
|
|
114
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
115
|
+
if (decorator = decorators[i])
|
|
116
|
+
result = (decorator(result)) || result;
|
|
117
|
+
return result;
|
|
118
|
+
};
|
|
119
|
+
var __decorateParam$1 = (index, decorator) => (target, key) => decorator(target, key, index);
|
|
120
|
+
let GraphQLErrorClass;
|
|
121
|
+
function getGraphQLError() {
|
|
122
|
+
if (!GraphQLErrorClass) {
|
|
123
|
+
try {
|
|
124
|
+
GraphQLErrorClass = require("graphql").GraphQLError;
|
|
125
|
+
} catch (_error) {
|
|
126
|
+
throw new Error(
|
|
127
|
+
"graphql is required for GraphQL support. Please install it: npm install graphql"
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return GraphQLErrorClass;
|
|
132
|
+
}
|
|
133
|
+
let WsException;
|
|
134
|
+
function getWsException() {
|
|
135
|
+
if (!WsException) {
|
|
136
|
+
try {
|
|
137
|
+
WsException = require("@nestjs/websockets").WsException;
|
|
138
|
+
} catch (_error) {
|
|
139
|
+
throw new Error(
|
|
140
|
+
"@nestjs/websockets is required for WebSocket support. Please install it: npm install @nestjs/websockets @nestjs/platform-socket.io"
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return WsException;
|
|
145
|
+
}
|
|
146
|
+
const AuthContextErrorMap = {
|
|
147
|
+
http: {
|
|
148
|
+
UNAUTHORIZED: (args) => new common.UnauthorizedException(
|
|
149
|
+
args ?? {
|
|
150
|
+
code: "UNAUTHORIZED",
|
|
151
|
+
message: "Unauthorized"
|
|
152
|
+
}
|
|
153
|
+
),
|
|
154
|
+
FORBIDDEN: (args) => new common.ForbiddenException(
|
|
155
|
+
args ?? {
|
|
156
|
+
code: "FORBIDDEN",
|
|
157
|
+
message: "Insufficient permissions"
|
|
158
|
+
}
|
|
159
|
+
)
|
|
160
|
+
},
|
|
161
|
+
graphql: {
|
|
162
|
+
UNAUTHORIZED: (args) => {
|
|
163
|
+
const GraphQLError = getGraphQLError();
|
|
164
|
+
if (typeof args === "string") {
|
|
165
|
+
return new GraphQLError(args);
|
|
166
|
+
} else if (typeof args === "object") {
|
|
167
|
+
return new GraphQLError(
|
|
168
|
+
// biome-ignore lint: if `message` is not set, a default is already in place.
|
|
169
|
+
args?.message ?? "Unauthorized",
|
|
170
|
+
args
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
return new GraphQLError("Unauthorized");
|
|
174
|
+
},
|
|
175
|
+
FORBIDDEN: (args) => {
|
|
176
|
+
const GraphQLError = getGraphQLError();
|
|
177
|
+
if (typeof args === "string") {
|
|
178
|
+
return new GraphQLError(args);
|
|
179
|
+
} else if (typeof args === "object") {
|
|
180
|
+
return new GraphQLError(
|
|
181
|
+
// biome-ignore lint: if `message` is not set, a default is already in place.
|
|
182
|
+
args?.message ?? "Forbidden",
|
|
183
|
+
args
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
return new GraphQLError("Forbidden");
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
ws: {
|
|
190
|
+
UNAUTHORIZED: (args) => {
|
|
191
|
+
const WsExceptionClass = getWsException();
|
|
192
|
+
return new WsExceptionClass(args ?? "UNAUTHORIZED");
|
|
193
|
+
},
|
|
194
|
+
FORBIDDEN: (args) => {
|
|
195
|
+
const WsExceptionClass = getWsException();
|
|
196
|
+
return new WsExceptionClass(args ?? "FORBIDDEN");
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
rpc: {
|
|
200
|
+
UNAUTHORIZED: () => new Error("UNAUTHORIZED"),
|
|
201
|
+
FORBIDDEN: () => new Error("FORBIDDEN")
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
exports.AuthGuard = class AuthGuard {
|
|
205
|
+
constructor(reflector, options) {
|
|
206
|
+
this.reflector = reflector;
|
|
207
|
+
this.options = options;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Validates if the current request is authenticated
|
|
211
|
+
* Attaches session and user information to the request object
|
|
212
|
+
* Supports HTTP, GraphQL and WebSocket execution contexts
|
|
213
|
+
* @param context - The execution context of the current request
|
|
214
|
+
* @returns True if the request is authorized to proceed, throws an error otherwise
|
|
215
|
+
*/
|
|
216
|
+
async canActivate(context) {
|
|
217
|
+
const request = getRequestFromContext(context);
|
|
218
|
+
const session = await this.options.auth.api.getSession({
|
|
219
|
+
headers: node.fromNodeHeaders(
|
|
220
|
+
request.headers || request?.handshake?.headers || []
|
|
221
|
+
)
|
|
222
|
+
});
|
|
223
|
+
request.session = session;
|
|
224
|
+
request.user = session?.user ?? null;
|
|
225
|
+
const isPublic = this.reflector.getAllAndOverride("PUBLIC", [
|
|
226
|
+
context.getHandler(),
|
|
227
|
+
context.getClass()
|
|
228
|
+
]);
|
|
229
|
+
if (isPublic) return true;
|
|
230
|
+
const isOptional = this.reflector.getAllAndOverride("OPTIONAL", [
|
|
231
|
+
context.getHandler(),
|
|
232
|
+
context.getClass()
|
|
233
|
+
]);
|
|
234
|
+
if (!session && isOptional) return true;
|
|
235
|
+
const ctxType = context.getType();
|
|
236
|
+
if (!session) throw AuthContextErrorMap[ctxType].UNAUTHORIZED();
|
|
237
|
+
const headers = node.fromNodeHeaders(
|
|
238
|
+
request.headers || request?.handshake?.headers || []
|
|
239
|
+
);
|
|
240
|
+
const requiredRoles = this.reflector.getAllAndOverride("ROLES", [
|
|
241
|
+
context.getHandler(),
|
|
242
|
+
context.getClass()
|
|
243
|
+
]);
|
|
244
|
+
if (requiredRoles && requiredRoles.length > 0) {
|
|
245
|
+
const hasRole = this.checkUserRole(session, requiredRoles);
|
|
246
|
+
if (!hasRole) throw AuthContextErrorMap[ctxType].FORBIDDEN();
|
|
247
|
+
}
|
|
248
|
+
const requiredOrgRoles = this.reflector.getAllAndOverride(
|
|
249
|
+
"ORG_ROLES",
|
|
250
|
+
[context.getHandler(), context.getClass()]
|
|
251
|
+
);
|
|
252
|
+
if (requiredOrgRoles && requiredOrgRoles.length > 0) {
|
|
253
|
+
const hasOrgRole = await this.checkOrgRole(
|
|
254
|
+
session,
|
|
255
|
+
headers,
|
|
256
|
+
requiredOrgRoles
|
|
257
|
+
);
|
|
258
|
+
if (!hasOrgRole) throw AuthContextErrorMap[ctxType].FORBIDDEN();
|
|
259
|
+
}
|
|
260
|
+
return true;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Checks if a role value matches any of the required roles
|
|
264
|
+
* Handles both array and comma-separated string role formats
|
|
265
|
+
* @param role - The role value to check (string, array, or undefined)
|
|
266
|
+
* @param requiredRoles - Array of roles that grant access
|
|
267
|
+
* @returns True if the role matches any required role
|
|
268
|
+
*/
|
|
269
|
+
matchesRequiredRole(role, requiredRoles) {
|
|
270
|
+
if (!role) return false;
|
|
271
|
+
if (Array.isArray(role)) {
|
|
272
|
+
return role.some((r) => requiredRoles.includes(r));
|
|
273
|
+
}
|
|
274
|
+
if (typeof role === "string") {
|
|
275
|
+
return role.split(",").some((r) => requiredRoles.includes(r.trim()));
|
|
276
|
+
}
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Fetches the user's role within an organization from the member table
|
|
281
|
+
* Uses Better Auth's organization plugin API if available
|
|
282
|
+
* @param headers - The request headers containing session cookies
|
|
283
|
+
* @returns The member's role in the organization, or undefined if not found
|
|
284
|
+
*/
|
|
285
|
+
async getMemberRoleInOrganization(headers) {
|
|
286
|
+
try {
|
|
287
|
+
const authApi = this.options.auth.api;
|
|
288
|
+
if (typeof authApi.getActiveMemberRole === "function") {
|
|
289
|
+
const result = await authApi.getActiveMemberRole({ headers });
|
|
290
|
+
return result?.role;
|
|
291
|
+
}
|
|
292
|
+
if (typeof authApi.getActiveMember === "function") {
|
|
293
|
+
const member = await authApi.getActiveMember({ headers });
|
|
294
|
+
return member?.role;
|
|
295
|
+
}
|
|
296
|
+
return void 0;
|
|
297
|
+
} catch (error) {
|
|
298
|
+
throw error;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Checks if the user has any of the required roles in user.role only.
|
|
303
|
+
* Used by @Roles() decorator for system-level role checks (admin plugin).
|
|
304
|
+
* @param session - The user's session
|
|
305
|
+
* @param requiredRoles - Array of roles that grant access
|
|
306
|
+
* @returns True if user.role matches any required role
|
|
307
|
+
*/
|
|
308
|
+
checkUserRole(session, requiredRoles) {
|
|
309
|
+
return this.matchesRequiredRole(session.user.role, requiredRoles);
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Checks if the user has any of the required roles in their organization.
|
|
313
|
+
* Used by @OrgRoles() decorator for organization-level role checks.
|
|
314
|
+
* Requires an active organization in the session.
|
|
315
|
+
* @param session - The user's session
|
|
316
|
+
* @param headers - The request headers for API calls
|
|
317
|
+
* @param requiredRoles - Array of roles that grant access
|
|
318
|
+
* @returns True if org member role matches any required role
|
|
319
|
+
*/
|
|
320
|
+
async checkOrgRole(session, headers, requiredRoles) {
|
|
321
|
+
const activeOrgId = session.session?.activeOrganizationId;
|
|
322
|
+
if (!activeOrgId) {
|
|
323
|
+
return false;
|
|
324
|
+
}
|
|
325
|
+
try {
|
|
326
|
+
const memberRole = await this.getMemberRoleInOrganization(headers);
|
|
327
|
+
return this.matchesRequiredRole(memberRole, requiredRoles);
|
|
328
|
+
} catch (error) {
|
|
329
|
+
console.error("Organization plugin error:", error);
|
|
330
|
+
return false;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
exports.AuthGuard = __decorateClass$1([
|
|
335
|
+
common.Injectable(),
|
|
336
|
+
__decorateParam$1(0, common.Inject(core.Reflector)),
|
|
337
|
+
__decorateParam$1(1, common.Inject(MODULE_OPTIONS_TOKEN))
|
|
338
|
+
], exports.AuthGuard);
|
|
339
|
+
|
|
340
|
+
const rawBodyParser = (req, _res, buffer) => {
|
|
341
|
+
if (Buffer.isBuffer(buffer)) {
|
|
342
|
+
req.rawBody = buffer;
|
|
343
|
+
}
|
|
344
|
+
return true;
|
|
345
|
+
};
|
|
346
|
+
function SkipBodyParsingMiddleware(options = {}) {
|
|
347
|
+
const { basePath = "/api/auth", enableRawBodyParser = false } = options;
|
|
348
|
+
const jsonParserOptions = enableRawBodyParser ? { verify: rawBodyParser } : {};
|
|
349
|
+
return (req, res, next) => {
|
|
350
|
+
if (req.baseUrl.startsWith(basePath)) {
|
|
351
|
+
next();
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
express__namespace.json(jsonParserOptions)(req, res, (err) => {
|
|
355
|
+
if (err) {
|
|
356
|
+
next(err);
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
express__namespace.urlencoded({ extended: true })(req, res, next);
|
|
360
|
+
});
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
365
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
366
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
367
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
368
|
+
if (decorator = decorators[i])
|
|
369
|
+
result = (decorator(result)) || result;
|
|
370
|
+
return result;
|
|
371
|
+
};
|
|
372
|
+
var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
|
|
373
|
+
const HOOKS = [
|
|
374
|
+
{ metadataKey: BEFORE_HOOK_KEY, hookType: "before" },
|
|
375
|
+
{ metadataKey: AFTER_HOOK_KEY, hookType: "after" }
|
|
376
|
+
];
|
|
377
|
+
exports.AuthModule = class AuthModule extends ConfigurableModuleClass {
|
|
378
|
+
constructor(applicationConfig, discoveryService, metadataScanner, adapter, options) {
|
|
379
|
+
super();
|
|
380
|
+
this.applicationConfig = applicationConfig;
|
|
381
|
+
this.discoveryService = discoveryService;
|
|
382
|
+
this.metadataScanner = metadataScanner;
|
|
383
|
+
this.adapter = adapter;
|
|
384
|
+
this.options = options;
|
|
385
|
+
this.basePath = shared_utils_js.normalizePath(
|
|
386
|
+
this.options.auth.options.basePath ?? "/api/auth"
|
|
387
|
+
);
|
|
388
|
+
const globalPrefixOptions = this.applicationConfig.getGlobalPrefixOptions();
|
|
389
|
+
this.applicationConfig.setGlobalPrefixOptions({
|
|
390
|
+
exclude: [
|
|
391
|
+
...globalPrefixOptions.exclude ?? [],
|
|
392
|
+
...utils_js.mapToExcludeRoute([this.basePath])
|
|
393
|
+
]
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
logger = new common.Logger(exports.AuthModule.name);
|
|
397
|
+
basePath;
|
|
398
|
+
onModuleInit() {
|
|
399
|
+
const providers = this.discoveryService.getProviders().filter(
|
|
400
|
+
({ metatype }) => metatype && Reflect.getMetadata(HOOK_KEY, metatype)
|
|
401
|
+
);
|
|
402
|
+
const hasHookProviders = providers.length > 0;
|
|
403
|
+
const hooksConfigured = typeof this.options.auth?.options?.hooks === "object";
|
|
404
|
+
if (hasHookProviders && !hooksConfigured)
|
|
405
|
+
throw new Error(
|
|
406
|
+
"Detected @Hook providers but Better Auth 'hooks' are not configured. Add 'hooks: {}' to your betterAuth(...) options."
|
|
407
|
+
);
|
|
408
|
+
if (!hooksConfigured) return;
|
|
409
|
+
for (const provider of providers) {
|
|
410
|
+
const providerPrototype = Object.getPrototypeOf(provider.instance);
|
|
411
|
+
const methods = this.metadataScanner.getAllMethodNames(providerPrototype);
|
|
412
|
+
for (const method of methods) {
|
|
413
|
+
const providerMethod = providerPrototype[method];
|
|
414
|
+
this.setupHooks(providerMethod, provider.instance);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
configure(consumer) {
|
|
419
|
+
const trustedOrigins = this.options.auth.options.trustedOrigins;
|
|
420
|
+
const isNotFunctionBased = trustedOrigins && Array.isArray(trustedOrigins);
|
|
421
|
+
if (!this.options.disableTrustedOriginsCors && isNotFunctionBased) {
|
|
422
|
+
this.adapter.httpAdapter.enableCors({
|
|
423
|
+
origin: trustedOrigins,
|
|
424
|
+
methods: ["GET", "POST", "PUT", "DELETE"],
|
|
425
|
+
credentials: true
|
|
426
|
+
});
|
|
427
|
+
} else if (trustedOrigins && !this.options.disableTrustedOriginsCors && !isNotFunctionBased)
|
|
428
|
+
throw new Error(
|
|
429
|
+
"Function-based trustedOrigins not supported in NestJS. Use string array or disable CORS with disableTrustedOriginsCors: true."
|
|
430
|
+
);
|
|
431
|
+
if (!this.options.disableBodyParser) {
|
|
432
|
+
consumer.apply(
|
|
433
|
+
SkipBodyParsingMiddleware({
|
|
434
|
+
basePath: this.basePath,
|
|
435
|
+
enableRawBodyParser: this.options.enableRawBodyParser
|
|
436
|
+
})
|
|
437
|
+
).forRoutes("*path");
|
|
438
|
+
}
|
|
439
|
+
const handler = node.toNodeHandler(this.options.auth);
|
|
440
|
+
consumer.apply((req, res) => {
|
|
441
|
+
if (this.options.middleware) {
|
|
442
|
+
return this.options.middleware(req, res, () => handler(req, res));
|
|
443
|
+
}
|
|
444
|
+
return handler(req, res);
|
|
445
|
+
}).forRoutes(this.basePath);
|
|
446
|
+
this.logger.log(`AuthModule initialized BetterAuth on '${this.basePath}'`);
|
|
447
|
+
}
|
|
448
|
+
setupHooks(providerMethod, providerClass) {
|
|
449
|
+
if (!this.options.auth.options.hooks) return;
|
|
450
|
+
for (const { metadataKey, hookType } of HOOKS) {
|
|
451
|
+
const hasHook = Reflect.hasMetadata(metadataKey, providerMethod);
|
|
452
|
+
if (!hasHook) continue;
|
|
453
|
+
const hookPath = Reflect.getMetadata(metadataKey, providerMethod);
|
|
454
|
+
const originalHook = this.options.auth.options.hooks[hookType];
|
|
455
|
+
this.options.auth.options.hooks[hookType] = plugins.createAuthMiddleware(
|
|
456
|
+
async (ctx) => {
|
|
457
|
+
if (originalHook) {
|
|
458
|
+
await originalHook(ctx);
|
|
459
|
+
}
|
|
460
|
+
if (hookPath && hookPath !== ctx.path) return;
|
|
461
|
+
await providerMethod.apply(providerClass, [ctx]);
|
|
462
|
+
}
|
|
463
|
+
);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
static forRootAsync(options) {
|
|
467
|
+
const forRootAsyncResult = super.forRootAsync(options);
|
|
468
|
+
const { module } = forRootAsyncResult;
|
|
469
|
+
return {
|
|
470
|
+
...forRootAsyncResult,
|
|
471
|
+
module: options.disableControllers ? AuthModuleWithoutControllers : module,
|
|
472
|
+
controllers: options.disableControllers ? [] : forRootAsyncResult.controllers,
|
|
473
|
+
providers: [
|
|
474
|
+
...forRootAsyncResult.providers ?? [],
|
|
475
|
+
...!options.disableGlobalAuthGuard ? [
|
|
476
|
+
{
|
|
477
|
+
provide: core.APP_GUARD,
|
|
478
|
+
useClass: exports.AuthGuard
|
|
479
|
+
}
|
|
480
|
+
] : []
|
|
481
|
+
]
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
static forRoot(arg1, arg2) {
|
|
485
|
+
const normalizedOptions = typeof arg1 === "object" && arg1 !== null && "auth" in arg1 ? arg1 : { ...arg2 ?? {}, auth: arg1 };
|
|
486
|
+
const forRootResult = super.forRoot(normalizedOptions);
|
|
487
|
+
const { module } = forRootResult;
|
|
488
|
+
return {
|
|
489
|
+
...forRootResult,
|
|
490
|
+
module: normalizedOptions.disableControllers ? AuthModuleWithoutControllers : module,
|
|
491
|
+
controllers: normalizedOptions.disableControllers ? [] : forRootResult.controllers,
|
|
492
|
+
providers: [
|
|
493
|
+
...forRootResult.providers ?? [],
|
|
494
|
+
...!normalizedOptions.disableGlobalAuthGuard ? [
|
|
495
|
+
{
|
|
496
|
+
provide: core.APP_GUARD,
|
|
497
|
+
useClass: exports.AuthGuard
|
|
498
|
+
}
|
|
499
|
+
] : []
|
|
500
|
+
]
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
};
|
|
504
|
+
exports.AuthModule = __decorateClass([
|
|
505
|
+
common.Module({
|
|
506
|
+
imports: [core.DiscoveryModule],
|
|
507
|
+
providers: [exports.AuthService],
|
|
508
|
+
exports: [exports.AuthService]
|
|
509
|
+
}),
|
|
510
|
+
__decorateParam(0, common.Inject(core.ApplicationConfig)),
|
|
511
|
+
__decorateParam(1, common.Inject(core.DiscoveryService)),
|
|
512
|
+
__decorateParam(2, common.Inject(core.MetadataScanner)),
|
|
513
|
+
__decorateParam(3, common.Inject(core.HttpAdapterHost)),
|
|
514
|
+
__decorateParam(4, common.Inject(MODULE_OPTIONS_TOKEN))
|
|
515
|
+
], exports.AuthModule);
|
|
516
|
+
class AuthModuleWithoutControllers extends exports.AuthModule {
|
|
517
|
+
configure() {
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
exports.AFTER_HOOK_KEY = AFTER_HOOK_KEY;
|
|
523
|
+
exports.AUTH_MODULE_OPTIONS_KEY = AUTH_MODULE_OPTIONS_KEY;
|
|
524
|
+
exports.AfterHook = AfterHook;
|
|
525
|
+
exports.AllowAnonymous = AllowAnonymous;
|
|
526
|
+
exports.BEFORE_HOOK_KEY = BEFORE_HOOK_KEY;
|
|
527
|
+
exports.BeforeHook = BeforeHook;
|
|
528
|
+
exports.HOOK_KEY = HOOK_KEY;
|
|
529
|
+
exports.Hook = Hook;
|
|
530
|
+
exports.Optional = Optional;
|
|
531
|
+
exports.OptionalAuth = OptionalAuth;
|
|
532
|
+
exports.OrgRoles = OrgRoles;
|
|
533
|
+
exports.Public = Public;
|
|
534
|
+
exports.Roles = Roles;
|
|
535
|
+
exports.Session = Session;
|