Calling DbAuthHandler

I was playing around with the api/src/functions/auth.js code e and noticed that if I change the login logic a little bit and add the following lines inside this code:

// rest of the api/src/functions/auth.js code
authHandler.login = async () => {
    const user = {
      id: Id_of_user_in_database,
      email: Email_of_user_in_database,
    }
    const loginResponse = authHandler._loginResponse(user)
    return loginResponse

  }
// remaining of the api/src/functions/auth.js code

It still allows the user to login without providing the password, etc. Is this the expected behavior? I was surprised to see the user logged in on the front end side. Curious to know whether this behavior is normal.

Hey @rouzbeh, I’m happy to look into this. Could you provide more exact details so I could reproduce? E.g. Is the example below a faithful reproduction of where you added the login function to the authHandler? And then how did you trigger login on the frontend? Just using the dbAuth generator? Thanks!

  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',
    },

    // 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: {
      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',
    },

    forgotPassword: forgotPasswordOptions,
    login: loginOptions,
    resetPassword: resetPasswordOptions,
    signup: signupOptions,
  })

+  authHandler.login = async () => {
+    const user = {
+      id: Id_of_user_in_database,
+      email: Email_of_user_in_database,
+    }
+    const loginResponse = authHandler._loginResponse(user)
+    return loginResponse
+  }

  return await authHandler.invoke()
}

1 Like

Hi @dom
Thanks for checking this. Yes this is a fair representation. Please just make sure to add the actual values for one sample user instead Id_of_user_in_database and Email_of_user_in_database.
Just so you know this is a dbAuth implementation.
On the front you just enter some random username and password that doesn’t even exist in the database. Just make sure that it satisfies the password and username requirements like capital letter, numbers, etc.

Thanks.

Thanks @rouzbeh. I can reproduce this. And to answer your question of is this behavior normal, from a JavaScript perspective I’d say yes. We’re re-assigning the authHandler’s login function to one we made which logs anyone in as that user.

Here’s authHandler’s the login method:

Are you concerned that it’s not a private method or something like that? That we shouldn’t allow it to be re-assigned at all?

Thanks for verifying this @dom
My concern is of the security. Should the login method be able to login the user only based on the id and email without password?

Ah I see your concern. We’re getting into the internals of dbAuth at this point. I’m not the expert here and I should defer to @rob who implemented it. But I’ll take a stab at explaining it.

Let me paste the code snippet here again for reference:

authHandler.login = async () => {
    const user = {
      id: Id_of_user_in_database,
      email: Email_of_user_in_database,
    }
    const loginResponse = authHandler._loginResponse(user)
    return loginResponse

  }

The way dbAuth works, if you return a loginResponse with a valid user object, that user is logged in. The default dbAuth implementation doesn’t do this without checking that the credentials provided match of course. But this login implementation doesn’t check the credentials at all and just returns a valid user.

Again defer to @rob, but I don’t see this as a security concern. If you’re concerned about the existing login flow that does check credentials (the one I linked to above), we’re definitely happy to discuss any concerns there.

1 Like

It’s been a while since I worked in this code, but I’m pretty sure the authHandler.login() will only be invoked if the username and password from the login page matches a user in the database. If you choose to return a DIFFERENT user from this function, you can do that, but in the default case you return the same user that’s given to the login() function (the one that passed the username/password check).

As far as security I wouldn’t say this is any more of a concern than anything a developer in full control of the code could do…you could expose the whole database on a page of your app if you really wanted to! But you shouldn’t. :sweat_smile:

1 Like

@dom @rob
Thanks for the explanation. Fair enough!