forked from redwoodjs/redwood
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' of github.com:redwoodjs/redwood into feat/re-expo…
…rt-serverStore * 'main' of github.com:redwoodjs/redwood: chore(comment): Remove comment that's wrong (redwoodjs#10912) chore(esm): Fix project-config dual packaging (redwoodjs#10901) RSC: dbAuth in kitchen-sink (redwoodjs#10907) RSC: No need to pass location to Router anymore (redwoodjs#10905) RSC: Make `rw g page` work for RSC projects (redwoodjs#10903) Updates document template to use exports field for htmlTags (redwoodjs#10902)
- Loading branch information
Showing
52 changed files
with
1,433 additions
and
78 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
14 changes: 14 additions & 0 deletions
14
...es__/test-project-rsc-kitchen-sink/api/db/migrations/20240702231421_db_auth/migration.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
-- CreateTable | ||
CREATE TABLE "User" ( | ||
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, | ||
"email" TEXT NOT NULL, | ||
"hashedPassword" TEXT NOT NULL, | ||
"salt" TEXT NOT NULL, | ||
"resetToken" TEXT, | ||
"resetTokenExpiresAt" DATETIME, | ||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
"updatedAt" DATETIME NOT NULL | ||
); | ||
|
||
-- CreateIndex | ||
CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
207 changes: 207 additions & 0 deletions
207
__fixtures__/test-project-rsc-kitchen-sink/api/src/functions/auth.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
import type { APIGatewayProxyEvent, Context } from 'aws-lambda' | ||
|
||
import { DbAuthHandler } from '@redwoodjs/auth-dbauth-api' | ||
import type { DbAuthHandlerOptions, UserType } from '@redwoodjs/auth-dbauth-api' | ||
|
||
import { cookieName } from 'src/lib/auth' | ||
import { db } from 'src/lib/db' | ||
|
||
export const handler = async ( | ||
event: APIGatewayProxyEvent, | ||
context: Context | ||
) => { | ||
const forgotPasswordOptions: DbAuthHandlerOptions['forgotPassword'] = { | ||
// handler() is invoked after verifying that a user was found with the given | ||
// username. This is where you can send the user an email with a link to | ||
// reset their password. With the default dbAuth routes and field names, the | ||
// URL to reset the password will be: | ||
// | ||
// https://example.com/reset-password?resetToken=${user.resetToken} | ||
// | ||
// Whatever is returned from this function will be returned from | ||
// the `forgotPassword()` function that is destructured from `useAuth()`. | ||
// You could use this return value to, for example, show the email | ||
// address in a toast message so the user will know it worked and where | ||
// to look for the email. | ||
// | ||
// Note that this return value is sent to the client in *plain text* | ||
// so don't include anything you wouldn't want prying eyes to see. The | ||
// `user` here has been sanitized to only include the fields listed in | ||
// `allowedUserFields` so it should be safe to return as-is. | ||
handler: (user, _resetToken) => { | ||
// TODO: Send user an email/message with a link to reset their password, | ||
// including the `resetToken`. The URL should look something like: | ||
// `http://localhost:8910/reset-password?resetToken=${resetToken}` | ||
|
||
return user | ||
}, | ||
|
||
// How long the resetToken is valid for, in seconds (default is 24 hours) | ||
expires: 60 * 60 * 24, | ||
|
||
errors: { | ||
// for security reasons you may want to be vague here rather than expose | ||
// the fact that the email address wasn't found (prevents fishing for | ||
// valid email addresses) | ||
usernameNotFound: 'Username not found', | ||
// if the user somehow gets around client validation | ||
usernameRequired: 'Username is required', | ||
}, | ||
} | ||
|
||
const loginOptions: DbAuthHandlerOptions['login'] = { | ||
// handler() is called after finding the user that matches the | ||
// username/password provided at login, but before actually considering them | ||
// logged in. The `user` argument will be the user in the database that | ||
// matched the username/password. | ||
// | ||
// If you want to allow this user to log in simply return the user. | ||
// | ||
// If you want to prevent someone logging in for another reason (maybe they | ||
// didn't validate their email yet), throw an error and it will be returned | ||
// by the `logIn()` function from `useAuth()` in the form of: | ||
// `{ message: 'Error message' }` | ||
handler: (user) => { | ||
return user | ||
}, | ||
|
||
errors: { | ||
usernameOrPasswordMissing: 'Both username and password are required', | ||
usernameNotFound: 'Username ${username} not found', | ||
// For security reasons you may want to make this the same as the | ||
// usernameNotFound error so that a malicious user can't use the error | ||
// to narrow down if it's the username or password that's incorrect | ||
incorrectPassword: 'Incorrect password for ${username}', | ||
}, | ||
|
||
// How long a user will remain logged in, in seconds | ||
expires: 60 * 60 * 24 * 365 * 10, | ||
} | ||
|
||
const resetPasswordOptions: DbAuthHandlerOptions['resetPassword'] = { | ||
// handler() is invoked after the password has been successfully updated in | ||
// the database. Returning anything truthy will automatically log the user | ||
// in. Return `false` otherwise, and in the Reset Password page redirect the | ||
// user to the login page. | ||
handler: (_user) => { | ||
return true | ||
}, | ||
|
||
// If `false` then the new password MUST be different from the current one | ||
allowReusedPassword: true, | ||
|
||
errors: { | ||
// the resetToken is valid, but expired | ||
resetTokenExpired: 'resetToken is expired', | ||
// no user was found with the given resetToken | ||
resetTokenInvalid: 'resetToken is invalid', | ||
// the resetToken was not present in the URL | ||
resetTokenRequired: 'resetToken is required', | ||
// new password is the same as the old password (apparently they did not forget it) | ||
reusedPassword: 'Must choose a new password', | ||
}, | ||
} | ||
|
||
interface UserAttributes { | ||
name: string | ||
} | ||
|
||
const signupOptions: DbAuthHandlerOptions< | ||
UserType, | ||
UserAttributes | ||
>['signup'] = { | ||
// Whatever you want to happen to your data on new user signup. Redwood will | ||
// check for duplicate usernames before calling this handler. At a minimum | ||
// you need to save the `username`, `hashedPassword` and `salt` to your | ||
// user table. `userAttributes` contains any additional object members that | ||
// were included in the object given to the `signUp()` function you got | ||
// from `useAuth()`. | ||
// | ||
// If you want the user to be immediately logged in, return the user that | ||
// was created. | ||
// | ||
// If this handler throws an error, it will be returned by the `signUp()` | ||
// function in the form of: `{ error: 'Error message' }`. | ||
// | ||
// If this returns anything else, it will be returned by the | ||
// `signUp()` function in the form of: `{ message: 'String here' }`. | ||
handler: ({ | ||
username, | ||
hashedPassword, | ||
salt, | ||
userAttributes: _userAttributes, | ||
}) => { | ||
return db.user.create({ | ||
data: { | ||
email: username, | ||
hashedPassword: hashedPassword, | ||
salt: salt, | ||
// name: userAttributes.name | ||
}, | ||
}) | ||
}, | ||
|
||
// Include any format checks for password here. Return `true` if the | ||
// password is valid, otherwise throw a `PasswordValidationError`. | ||
// Import the error along with `DbAuthHandler` from `@redwoodjs/api` above. | ||
passwordValidation: (_password) => { | ||
return true | ||
}, | ||
|
||
errors: { | ||
// `field` will be either "username" or "password" | ||
fieldMissing: '${field} is required', | ||
usernameTaken: 'Username `${username}` already in use', | ||
}, | ||
} | ||
|
||
const authHandler = new DbAuthHandler(event, context, { | ||
// Provide prisma db client | ||
db: db, | ||
|
||
// The name of the property you'd call on `db` to access your user table. | ||
// i.e. if your Prisma model is named `User` this value would be `user`, as in `db.user` | ||
authModelAccessor: 'user', | ||
|
||
// A map of what dbAuth calls a field to what your database calls it. | ||
// `id` is whatever column you use to uniquely identify a user (probably | ||
// something like `id` or `userId` or even `email`) | ||
authFields: { | ||
id: 'id', | ||
username: 'email', | ||
hashedPassword: 'hashedPassword', | ||
salt: 'salt', | ||
resetToken: 'resetToken', | ||
resetTokenExpiresAt: 'resetTokenExpiresAt', | ||
}, | ||
|
||
// A list of fields on your user object that are safe to return to the | ||
// client when invoking a handler that returns a user (like forgotPassword | ||
// and signup). This list should be as small as possible to be sure not to | ||
// leak any sensitive information to the client. | ||
allowedUserFields: ['id', 'email'], | ||
|
||
// Specifies attributes on the cookie that dbAuth sets in order to remember | ||
// who is logged in. See https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies | ||
cookie: { | ||
attributes: { | ||
HttpOnly: true, | ||
Path: '/', | ||
SameSite: 'Strict', | ||
Secure: process.env.NODE_ENV !== 'development', | ||
|
||
// If you need to allow other domains (besides the api side) access to | ||
// the dbAuth session cookie: | ||
// Domain: 'example.com', | ||
}, | ||
name: cookieName, | ||
}, | ||
|
||
forgotPassword: forgotPasswordOptions, | ||
login: loginOptions, | ||
resetPassword: resetPasswordOptions, | ||
signup: signupOptions, | ||
}) | ||
|
||
return await authHandler.invoke() | ||
} |
6 changes: 6 additions & 0 deletions
6
__fixtures__/test-project-rsc-kitchen-sink/api/src/functions/graphql.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.