Skip to content

[Bug?]: Default dbAuth Forgot Password<-->Reset Password flow example password reset token URL Invalid #12040

@raleigh9123

Description

@raleigh9123

What's not working?

Under the current default setup of dbAuth, the forgotPasswordOptions handler in api/src/functions/auth.ts file lists an example url that incorrectly states an object to access the raw resetToken.

The default file generation looks like this:

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.
    handler: (user) => {
      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',
    },
  }

The example url suggests implementing an email link by accessing user.resetToken, but this returns undefined (presumably since only allowedUserFields are returned, though I'm not sure what values are attached to the user object, and what values are simply not allowed since this is resolved internally via the DbAuthHandlerOptions). IF, allowedUserFields includes 'resetToken', this token could be exposed to the user object, and would then result in an error as this would expose the hashed token in the url (and the reset password page/ validateToken() functions expect a raw token, that is then hashed and compared to the database hashed token).

In this case, event is the User object (of type UserType), and the context is the raw resetToken before it is hashed and stored in the database. This means that the correct example URL in the commented out example should exist within the handler function as follows:

handler: (user, context) => {
// Example URL should provide context, the raw resetToken, which would be sent via email, or text, etc, THEN return the user to the client with allowedUserFields to provide a verification to client UI (message successfully sent to ${user.email}!
// https://example.com/reset-password?resetToken=${context}
      return user
    },

I had to dig in the node modules .d.ts files to see how this handler function works in the auth.ts file, and it is unclear that the context within the forgotPasswordOptions returns the raw token 'resetToken' before it is hashed and stored in the db. This is due in part to the handler.d.ts file showing generic 'event', and 'context', values that are used across all of the individual handler() {} helper functions for each auth use case. The individual handler params returned within each function are not specified in the node modules ts files, and also do not have sufficient comments within the code blocks (at least for forgotPassword to show that the context would be the rawToken that would be used to actually reset a password).

I am also unsure if this should be classified as a bug, specifically, as it only provides a suggested code. However, if uncommented with a valid base url, the example URL within the function would result in an error.

How do we reproduce the bug?

From a fresh redwood installation using redwood version 8.6.1, I added auth via yarn rw setup auth dbAuth. This generated the above example within my api/src/functions/auth.ts file.

What's your environment? (If it applies)

System:
    OS: macOS 15.4
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.19.0 - /private/var/folders/pp/jhdtr7112wv2mmdj6vnwgnhr0000gn/T/xfs-56146c55/node
    Yarn: 4.6.0 - /private/var/folders/pp/jhdtr7112wv2mmdj6vnwgnhr0000gn/T/xfs-56146c55/yarn
  Databases:
    SQLite: 3.43.2 - /usr/bin/sqlite3
  Browsers:
    Chrome: 135.0.7049.96
    Safari: 18.4
  npmPackages:
    @redwoodjs/auth-dbauth-setup: 8.6.1 => 8.6.1 
    @redwoodjs/cli-storybook-vite: 8.6.1 => 8.6.1 
    @redwoodjs/core: 8.6.1 => 8.6.1 
    @redwoodjs/project-config: 8.6.1 => 8.6.1 
  redwood.toml:
    [web]
      title = "Redwood App"
      port = 8910
      apiUrl = "/.redwood/functions" # You can customize graphql and dbauth urls individually too: see https://redwoodjs.com/docs/app-configuration-redwood-toml#api-paths
      includeEnvironmentVariables = [
        # Add any ENV vars that should be available to the web side to this array
        # See https://redwoodjs.com/docs/environment-variables#web
      ]
    [api]
      port = 8911
    [browser]
      open = true
    [notifications]
      versionUpdates = ["latest"]

Are you interested in working on this?

  • I'm interested in working on this

Metadata

Metadata

Assignees

No one assigned

    Labels

    bug/needs-infoMore information is needed for reproduction

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions