@redmix/auth-dbauth-api 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Redmix
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 ADDED
@@ -0,0 +1,148 @@
1
+ # Authentication
2
+
3
+ ## Contributing
4
+
5
+ If you want to contribute a new auth provider integration we recommend you
6
+ start by implementing it as a custom auth provider in a Redwood App first. When
7
+ that works you can package it up as an npm package and publish it on your own.
8
+ You can then create a PR on this repo with support for your new auth provider
9
+ in our `yarn rw setup auth` cli command. The easiest option is probably to just
10
+ look at one of the existing auth providers in
11
+ `packages/cli/src/commands/setup/auth/providers` and the corresponding
12
+ templates in `../templates`.
13
+
14
+ If you need help setting up a custom auth provider there's more info in the
15
+ [auth docs](https://redwoodjs.com/docs/authentication).
16
+
17
+ ### Contributing to the base auth implementation
18
+
19
+ If you want to contribute to our auth implementation, the interface towards
20
+ both auth service providers and RW apps we recommend you start looking in
21
+ `authFactory.ts` and then continue to `AuthProvider.tsx`. `AuthProvider.tsx`
22
+ has most of our implementation together with all the custom hooks it uses.
23
+ Another file to be accustomed with is `AuthContext.ts`. The interface in there
24
+ has pretty good code comments, and is what will be exposed to RW apps.
25
+
26
+ ## getCurrentUser
27
+
28
+ `getCurrentUser` returns the user information together with
29
+ an optional collection of roles used by requireAuth() to check if the user is authenticated or has role-based access.
30
+
31
+ Use in conjunction with `requireAuth` in your services to check that a user is logged in, whether or not they are assigned a role, and optionally raise an error if they're not.
32
+
33
+ ```js
34
+ @param decoded - The decoded access token containing user info and JWT claims like `sub`
35
+ @param { token, SupportedAuthTypes type } - The access token itself as well as the auth provider type
36
+ @param { APIGatewayEvent event, Context context } - An object which contains information from the invoker
37
+ such as headers and cookies, and the context information about the invocation such as IP Address
38
+ ```
39
+
40
+ ### Examples
41
+
42
+ #### Checks if currentUser is authenticated
43
+
44
+ This example is the standard use of `getCurrentUser`.
45
+
46
+ ```js
47
+ export const getCurrentUser = async (
48
+ decoded,
49
+ { _token, _type },
50
+ { _event, _context },
51
+ ) => {
52
+ return { ...decoded, roles: parseJWT({ decoded }).roles }
53
+ }
54
+ ```
55
+
56
+ #### User details fetched via database query
57
+
58
+ ```js
59
+ export const getCurrentUser = async (decoded) => {
60
+ return await db.user.findUnique({ where: { decoded.email } })
61
+ }
62
+ ```
63
+
64
+ #### User info is decoded from the access token
65
+
66
+ ```js
67
+ export const getCurrentUser = async (decoded) => {
68
+ return { ...decoded }
69
+ }
70
+ ```
71
+
72
+ #### User info is contained in the decoded token and roles extracted
73
+
74
+ ```js
75
+ export const getCurrentUser = async (decoded) => {
76
+ return { ...decoded, roles: parseJWT({ decoded }).roles }
77
+ }
78
+ ```
79
+
80
+ #### User record query by email with namespaced app_metadata roles as Auth0 requires custom JWT claims to be namespaced
81
+
82
+ ```js
83
+ export const getCurrentUser = async (decoded) => {
84
+ const currentUser = await db.user.findUnique({
85
+ where: { email: decoded.email },
86
+ })
87
+
88
+ return {
89
+ ...currentUser,
90
+ roles: parseJWT({ decoded: decoded, namespace: NAMESPACE }).roles,
91
+ }
92
+ }
93
+ ```
94
+
95
+ #### User record query by an identity with app_metadata roles
96
+
97
+ ```js
98
+ const getCurrentUser = async (decoded) => {
99
+ const currentUser = await db.user.findUnique({
100
+ where: { userIdentity: decoded.sub },
101
+ })
102
+ return {
103
+ ...currentUser,
104
+ roles: parseJWT({ decoded: decoded }).roles,
105
+ }
106
+ }
107
+ ```
108
+
109
+ #### Cookies and other request information are available in the req parameter, just in case
110
+
111
+ ```js
112
+ const getCurrentUser = async (_decoded, _raw, { event, _context }) => {
113
+ const cookies = cookie(event.headers.cookies)
114
+ const session = cookies['my.cookie.name']
115
+ const currentUser = await db.sessions.findUnique({ where: { id: session } })
116
+ return currentUser
117
+ }
118
+ ```
119
+
120
+ ## requireAuth
121
+
122
+ Use `requireAuth` in your services to check that a user is logged in, whether or not they are assigned a role, and optionally raise an error if they're not.
123
+
124
+ ```js
125
+ @param {string=} roles - An optional role or list of roles
126
+ @param {string[]=} roles - An optional list of roles
127
+
128
+ @returns {boolean} - If the currentUser is authenticated (and assigned one of the given roles)
129
+
130
+ @throws {AuthenticationError} - If the currentUser is not authenticated
131
+ @throws {ForbiddenError} If the currentUser is not allowed due to role permissions
132
+ ```
133
+
134
+ ### Examples
135
+
136
+ #### Checks if currentUser is authenticated
137
+
138
+ ```js
139
+ requireAuth()
140
+ ```
141
+
142
+ #### Checks if currentUser is authenticated and assigned one of the given roles
143
+
144
+ ```js
145
+ requireAuth({ role: 'admin' })
146
+ requireAuth({ role: ['editor', 'author'] })
147
+ requireAuth({ role: ['publisher'] })
148
+ ```
@@ -0,0 +1,373 @@
1
+ import type { PrismaClient } from '@prisma/client';
2
+ import type { AuthenticationResponseJSON, RegistrationResponseJSON } from '@simplewebauthn/typescript-types';
3
+ import type { APIGatewayProxyEvent, Context as LambdaContext } from 'aws-lambda';
4
+ import type { CorsConfig, CorsContext, PartialRequest } from '@redmix/api';
5
+ interface SignupFlowOptions<TUserAttributes = Record<string, unknown>> {
6
+ /**
7
+ * Allow users to sign up. Defaults to true.
8
+ * Needs to be explicitly set to false to disable the flow
9
+ */
10
+ enabled?: boolean;
11
+ /**
12
+ * Whatever you want to happen to your data on new user signup. Redwood will
13
+ * check for duplicate usernames before calling this handler. At a minimum
14
+ * you need to save the `username`, `hashedPassword` and `salt` to your
15
+ * user table. `userAttributes` contains any additional object members that
16
+ * were included in the object given to the `signUp()` function you got
17
+ * from `useAuth()`
18
+ */
19
+ handler: (signupHandlerOptions: SignupHandlerOptions<TUserAttributes>) => any;
20
+ /**
21
+ * Validate the user-supplied password with whatever logic you want. Return
22
+ * `true` if valid, throw `PasswordValidationError` if not.
23
+ */
24
+ passwordValidation?: (password: string) => boolean;
25
+ /**
26
+ * Object containing error strings
27
+ */
28
+ errors?: {
29
+ fieldMissing?: string;
30
+ usernameTaken?: string;
31
+ flowNotEnabled?: string;
32
+ };
33
+ /**
34
+ * Allows the user to define if the UserCheck for their selected db provider should use case insensitive
35
+ */
36
+ usernameMatch?: string;
37
+ }
38
+ interface ForgotPasswordFlowOptions<TUser = UserType> {
39
+ /**
40
+ * Allow users to request a new password via a call to forgotPassword. Defaults to true.
41
+ * Needs to be explicitly set to false to disable the flow
42
+ */
43
+ enabled?: boolean;
44
+ handler: (user: TUser, token: string) => any;
45
+ errors?: {
46
+ usernameNotFound?: string;
47
+ usernameRequired?: string;
48
+ flowNotEnabled?: string;
49
+ };
50
+ expires: number;
51
+ }
52
+ interface LoginFlowOptions<TUser = UserType> {
53
+ /**
54
+ * Allow users to login. Defaults to true.
55
+ * Needs to be explicitly set to false to disable the flow
56
+ */
57
+ enabled?: boolean;
58
+ /**
59
+ * Anything you want to happen before logging the user in. This can include
60
+ * throwing an error to prevent login. If you do want to allow login, this
61
+ * function must return an object representing the user you want to be logged
62
+ * in, containing at least an `id` field (whatever named field was provided
63
+ * for `authFields.id`). For example: `return { id: user.id }`
64
+ */
65
+ handler: (user: TUser) => any;
66
+ /**
67
+ * Object containing error strings
68
+ */
69
+ errors?: {
70
+ usernameOrPasswordMissing?: string;
71
+ usernameNotFound?: string;
72
+ incorrectPassword?: string;
73
+ flowNotEnabled?: string;
74
+ };
75
+ /**
76
+ * How long a user will remain logged in, in seconds
77
+ */
78
+ expires: number;
79
+ /**
80
+ * Allows the user to define if the UserCheck for their selected db provider should use case insensitive
81
+ */
82
+ usernameMatch?: string;
83
+ }
84
+ interface ResetPasswordFlowOptions<TUser = UserType> {
85
+ /**
86
+ * Allow users to reset their password via a code from a call to forgotPassword. Defaults to true.
87
+ * Needs to be explicitly set to false to disable the flow
88
+ */
89
+ enabled?: boolean;
90
+ handler: (user: TUser) => boolean | Promise<boolean>;
91
+ allowReusedPassword: boolean;
92
+ errors?: {
93
+ resetTokenExpired?: string;
94
+ resetTokenInvalid?: string;
95
+ resetTokenRequired?: string;
96
+ reusedPassword?: string;
97
+ flowNotEnabled?: string;
98
+ };
99
+ }
100
+ interface WebAuthnFlowOptions {
101
+ enabled: boolean;
102
+ expires: number;
103
+ name: string;
104
+ domain: string;
105
+ origin: string;
106
+ timeout?: number;
107
+ type: 'any' | 'platform' | 'cross-platform';
108
+ credentialFields: {
109
+ id: string;
110
+ userId: string;
111
+ publicKey: string;
112
+ transports: string;
113
+ counter: string;
114
+ };
115
+ }
116
+ export type UserType = Record<string | number, any>;
117
+ export type DbAuthResponse = Promise<{
118
+ headers: {
119
+ [x: string]: string | string[];
120
+ };
121
+ body?: string | undefined;
122
+ statusCode: number;
123
+ }>;
124
+ type AuthMethodOutput = [
125
+ string | Record<string, any> | boolean | undefined,
126
+ Headers?,
127
+ {
128
+ statusCode: number;
129
+ }?
130
+ ];
131
+ export interface DbAuthHandlerOptions<TUser = UserType, TUserAttributes = Record<string, unknown>> {
132
+ /**
133
+ * Provide prisma db client
134
+ */
135
+ db: PrismaClient;
136
+ /**
137
+ * The name of the property you'd call on `db` to access your user table.
138
+ * ie. if your Prisma model is named `User` this value would be `user`, as in `db.user`
139
+ */
140
+ authModelAccessor: keyof PrismaClient;
141
+ /**
142
+ * The name of the property you'd call on `db` to access your user credentials table.
143
+ * ie. if your Prisma model is named `UserCredential` this value would be `userCredential`, as in `db.userCredential`
144
+ */
145
+ credentialModelAccessor?: keyof PrismaClient;
146
+ /**
147
+ * The fields that are allowed to be returned from the user table when
148
+ * invoking handlers that return a user object (like forgotPassword and signup)
149
+ * Defaults to `id` and `email` if not set at all.
150
+ */
151
+ allowedUserFields?: string[];
152
+ /**
153
+ * A map of what dbAuth calls a field to what your database calls it.
154
+ * `id` is whatever column you use to uniquely identify a user (probably
155
+ * something like `id` or `userId` or even `email`)
156
+ */
157
+ authFields: {
158
+ id: string;
159
+ username: string;
160
+ hashedPassword: string;
161
+ salt: string;
162
+ resetToken: string;
163
+ resetTokenExpiresAt: string;
164
+ challenge?: string;
165
+ };
166
+ /**
167
+ * Object containing cookie config options
168
+ */
169
+ cookie?: {
170
+ /** @deprecated set this option in `cookie.attributes` */
171
+ Path?: string;
172
+ /** @deprecated set this option in `cookie.attributes` */
173
+ HttpOnly?: boolean;
174
+ /** @deprecated set this option in `cookie.attributes` */
175
+ Secure?: boolean;
176
+ /** @deprecated set this option in `cookie.attributes` */
177
+ SameSite?: string;
178
+ /** @deprecated set this option in `cookie.attributes` */
179
+ Domain?: string;
180
+ attributes?: {
181
+ Path?: string;
182
+ HttpOnly?: boolean;
183
+ Secure?: boolean;
184
+ SameSite?: string;
185
+ Domain?: string;
186
+ };
187
+ /**
188
+ * The name of the cookie that dbAuth sets
189
+ *
190
+ * %port% will be replaced with the port the api server is running on.
191
+ * If you have multiple RW apps running on the same host, you'll need to
192
+ * make sure they all use unique cookie names
193
+ */
194
+ name?: string;
195
+ };
196
+ /**
197
+ * Object containing forgot password options
198
+ */
199
+ forgotPassword: ForgotPasswordFlowOptions<TUser> | {
200
+ enabled: false;
201
+ };
202
+ /**
203
+ * Object containing login options
204
+ */
205
+ login: LoginFlowOptions<TUser> | {
206
+ enabled: false;
207
+ };
208
+ /**
209
+ * Object containing reset password options
210
+ */
211
+ resetPassword: ResetPasswordFlowOptions<TUser> | {
212
+ enabled: false;
213
+ };
214
+ /**
215
+ * Object containing login options
216
+ */
217
+ signup: SignupFlowOptions<TUserAttributes> | {
218
+ enabled: false;
219
+ };
220
+ /**
221
+ * Object containing WebAuthn options
222
+ */
223
+ webAuthn?: WebAuthnFlowOptions | {
224
+ enabled: false;
225
+ };
226
+ /**
227
+ * CORS settings, same as in createGraphqlHandler
228
+ */
229
+ cors?: CorsConfig;
230
+ }
231
+ export interface SignupHandlerOptions<TUserAttributes> {
232
+ username: string;
233
+ hashedPassword: string;
234
+ salt: string;
235
+ userAttributes?: TUserAttributes;
236
+ }
237
+ export type AuthMethodNames = 'forgotPassword' | 'getToken' | 'login' | 'logout' | 'resetPassword' | 'signup' | 'webAuthnAuthenticate' | 'webAuthnAuthOptions' | 'webAuthnRegOptions' | 'webAuthnRegister' | 'validateResetToken';
238
+ type Params = AuthenticationResponseJSON & RegistrationResponseJSON & {
239
+ username?: string;
240
+ password?: string;
241
+ resetToken?: string;
242
+ method: AuthMethodNames;
243
+ [key: string]: any;
244
+ } & {
245
+ transports?: string;
246
+ };
247
+ type DbAuthSession<T = unknown> = Record<string, T>;
248
+ type CorsHeaders = Record<string, string>;
249
+ export declare class DbAuthHandler<TUser extends UserType, TUserAttributes = Record<string, unknown>> {
250
+ event: Request | APIGatewayProxyEvent;
251
+ _normalizedRequest: PartialRequest<Params> | undefined;
252
+ httpMethod: string;
253
+ options: DbAuthHandlerOptions<TUser, TUserAttributes>;
254
+ cookie: string;
255
+ db: PrismaClient;
256
+ dbAccessor: any;
257
+ dbCredentialAccessor: any;
258
+ allowedUserFields: string[];
259
+ hasInvalidSession: boolean;
260
+ session: DbAuthSession | undefined;
261
+ sessionCsrfToken: string | undefined;
262
+ corsContext: CorsContext | undefined;
263
+ sessionExpiresDate: string;
264
+ webAuthnExpiresDate: string;
265
+ encryptedSession: string | null;
266
+ createResponse: (response: {
267
+ body?: string;
268
+ statusCode: number;
269
+ headers?: Headers;
270
+ }, corsHeaders: CorsHeaders) => {
271
+ headers: Record<string, string | string[]>;
272
+ body?: string | undefined;
273
+ statusCode: number;
274
+ };
275
+ get normalizedRequest(): PartialRequest<Params>;
276
+ static get METHODS(): AuthMethodNames[];
277
+ static get VERBS(): {
278
+ forgotPassword: string;
279
+ getToken: string;
280
+ login: string;
281
+ logout: string;
282
+ resetPassword: string;
283
+ signup: string;
284
+ validateResetToken: string;
285
+ webAuthnRegOptions: string;
286
+ webAuthnRegister: string;
287
+ webAuthnAuthOptions: string;
288
+ webAuthnAuthenticate: string;
289
+ };
290
+ static get PAST_EXPIRES_DATE(): string;
291
+ static get CSRF_TOKEN(): string;
292
+ static get AVAILABLE_WEBAUTHN_TRANSPORTS(): string[];
293
+ /**
294
+ * Returns the set-cookie header to mark the cookie as expired ("deletes" the session)
295
+ *
296
+ * The header keys are case insensitive, but Fastify prefers these to be lowercase.
297
+ * Therefore, we want to ensure that the headers are always lowercase and unique
298
+ * for compliance with HTTP/2.
299
+ *
300
+ * @see: https://www.rfc-editor.org/rfc/rfc7540#section-8.1.2
301
+ */
302
+ get _deleteSessionHeader(): Headers;
303
+ constructor(event: APIGatewayProxyEvent | Request, _context: LambdaContext, // @TODO:
304
+ options: DbAuthHandlerOptions<TUser, TUserAttributes>);
305
+ init(): Promise<void>;
306
+ invoke(): Promise<{
307
+ headers: Record<string, string | string[]>;
308
+ body?: string | undefined;
309
+ statusCode: number;
310
+ }>;
311
+ forgotPassword(): Promise<AuthMethodOutput>;
312
+ getToken(): Promise<AuthMethodOutput>;
313
+ login(): Promise<AuthMethodOutput>;
314
+ logout(): AuthMethodOutput;
315
+ resetPassword(): Promise<AuthMethodOutput>;
316
+ signup(): Promise<AuthMethodOutput>;
317
+ validateResetToken(): Promise<AuthMethodOutput>;
318
+ webAuthnAuthenticate(): Promise<AuthMethodOutput>;
319
+ webAuthnAuthOptions(): Promise<AuthMethodOutput>;
320
+ webAuthnRegOptions(): Promise<AuthMethodOutput>;
321
+ webAuthnRegister(): Promise<AuthMethodOutput>;
322
+ _validateOptions(): void;
323
+ _saveChallenge(userId: string | number, value: string | null): Promise<void>;
324
+ _webAuthnCookie(id: string, expires: string): string;
325
+ _sanitizeUser(user: Record<string, unknown>): any;
326
+ _decodeEvent(): void;
327
+ _cookieAttributes({ expires, options, }: {
328
+ expires?: 'now' | string;
329
+ options?: DbAuthHandlerOptions['cookie'];
330
+ }): (string | null)[];
331
+ _createAuthProviderCookieString(): string;
332
+ _createSessionCookieString<TIdType = any>(data: DbAuthSession<TIdType>, csrfToken: string): string;
333
+ _validateCsrf(): Promise<boolean>;
334
+ _findUserByToken(token: string): Promise<any>;
335
+ _clearResetToken(user: Record<string, unknown>): Promise<void>;
336
+ _verifyUser(username: string | undefined, password: string | undefined): Promise<any>;
337
+ _verifyPassword(user: Record<string, unknown>, password: string): Promise<Record<string, unknown>>;
338
+ _getCurrentUser(): Promise<any>;
339
+ _createUser(): Promise<any>;
340
+ _getAuthMethod(): Promise<AuthMethodNames>;
341
+ _validateField(name: string, value: string | undefined): value is string;
342
+ _loginResponse(user: Record<string, any>, statusCode?: number): [{
343
+ id: string;
344
+ }, Headers, {
345
+ statusCode: number;
346
+ }];
347
+ _logoutResponse(response?: Record<string, unknown>): AuthMethodOutput;
348
+ _ok(body: string | boolean | undefined | Record<string, unknown>, headers?: Headers, options?: {
349
+ statusCode: number;
350
+ }): {
351
+ statusCode: number;
352
+ body: string;
353
+ headers: Headers;
354
+ };
355
+ _notFound(): {
356
+ statusCode: number;
357
+ };
358
+ _badRequest(message: string): {
359
+ statusCode: number;
360
+ body: string;
361
+ headers: Headers;
362
+ };
363
+ _getUserMatchCriteriaOptions(username: string, usernameMatchFlowOption: string | undefined): {
364
+ [x: string]: string;
365
+ } | {
366
+ [x: string]: {
367
+ equals: string;
368
+ mode: string;
369
+ };
370
+ };
371
+ }
372
+ export {};
373
+ //# sourceMappingURL=DbAuthHandler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DbAuthHandler.d.ts","sourceRoot":"","sources":["../src/DbAuthHandler.ts"],"names":[],"mappings":"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"}