How to do Custom Function Authentication without external provider? How to do case insensitive email/password auth?

I want an email/password authentication system, but with a specialty that’s not possible in the basic email/password auth provider: I don’t want case sensitive emails allowed.

If Example@e.com is already registered, I don’t want example@e.com to be able to register.

At the login, I want ANY casing of eXAmPle@e.com to work (if the password matches of course).

At the password reset, I want any casing to trigger the password reset email, BUT it has to be sent to the initial casing of the email address that was provided on registering. If user registered with Example@e.com, at the password reset someone puts example@e.com in the field, then the mail has to be sent to Example@e.com .

I guess that a custom function would be the best thing for this to work, but how exactly can I implement this?

Do I have to salt, hash the passwords myself? Do I have to do the session key thing myself? Do I have to encrypt the communication between Realm Server and Client SDKs myself?

Hi @SirSwagon_N_A ,

You have an example that might be altered a little to support what you described.

When user registered with email “Example@example.com” the registration will use an internal collection in login db to store this data with both lower case and origCase:

{
_id : ... , 
user : "example@example.com",
password : "Abc123",
origCase : " Example@example.com"
}

Then in this example the auth function needs to run toLowerCase() on the user:

exports = async function (payload) {
  // 1. Parse the `payload` object, which holds data from the
  //    FunctionCredential sent by the SDK.
  const { username, password } = payload;

  // 2. Get the user by lower case to ignore casing

  const userLogin = await context.services.get("<YOUR-CLUSTER-NAME>").db("login"). collection("users").findOne({user: username.toLowerCase(), password : password})

  // 3. Return a unique identifier for the user. Typically this is the
  //    user's ID in the external authentication system or the _id of a
  //    stored MongoDB document that describes them.
  //
  //    !!! This is NOT the user's internal account ID for your app !!!
  return userLogin._id;
};

This will find any case of this user. The reset password can still send back the origCase data while using the user field with lower case to find him.

Make sure to set a unique index on user field to not allow duplicate usernames.

Thanks
Pavel

Thank so much Pavel Duchovny for the answer!!!

I have some more simple questions but can’t find the answers:

  1. In this line
    const userLogin = await context.services.get("<YOUR-CLUSTER-NAME>").db("login"). collection("users").findOne({user: username.toLowerCase(), password : password})
    the db “login” and the collection “users” is that something I need to create myself or is that automatically created for every Realm App? And do I need to hash the password before saving it in this collection?

  2. If I call the loginAsync with the customFunctionCredentials in Java SDK, will it get encrypted automatically or will username and password be sent as plain text?

Credentials customFunctionCredentials =
 Credentials.customFunction(
  new org.bson.Document("username", "bob", "password", "password123"));
app.loginAsync(customFunctionCredentials, it -> {
    ...
});

Here it says
“MongoDB Atlas uses encryption in transit from application client to server and within intra-cluster communications by setting a set of certificates for the servers”
So my question is, does this also apply before the user is authenticated?

  1. Is the result return userLogin._id; that gets sent from server to user also encrypted automatically?

If you could answer these questions it would mean so much to me!

Hi @SirSwagon_N_A ,

The collection is something you need to create and manage, it will write new users on signup and check on login. Yes you have to provide the password in the payload as well.

i believe no payload especially auth payload is sent clear text. We encrypt it using built in sdk encryption, it has nothing to do with cluster encryption, it is separate TLS.

Look for some guides on working with app service auth on MongoDB Developer Center

Ty

1 Like

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.