Authentication Controller
Goal
The goal of the authentication controller is to handle different authentication requests from the front end (such as logging in, registering, and sending verification emails) as well as to update the user object in the database accordingly.
Current Setup
The authentication controller1 can be found at AnScealai/api/controllers/authentication.js. This file is required in the user route located at AnScealai/api/routes/user.route.js. When the front-end makes a request to the user route using the authentication service2, the route passes the request to the relevant function. The requests executed in the authentication service are redirected to functions in this authentication controller file (where the request url matches). These anonymous functions are exported as module exports3 so they can be imported into the user.route.js file. Some of the functions in this controller call on other functions defined directly in the User object Mongoose schema. These functions can be found in the User model at AnScealai/api/models/user.js4.
Usage
The authentication controller consists of the following anonymous functions that handle all the functionality for authenticating users. The functions may look long in the code, but the majority of the lines are dedicated to checking if certain variables exist and returning any error messages if/as they occur.
module.exports.login
This function takes in a user object to check if their status is Active. (The passport has already validated the user as existing in the DB). The function executes the following steps:
- Checks if there is a user (from the request object authenticated by the passport). If there is no user, the function returns with an error.
- Checks that the user has a valid account status (such as ‘Active’) by calling the validStatus() function (defined in the User model). If the user does not have an active status, their status is set to ‘Pending’ and the changes are saved in the DB.
- Checks if the user’s status is set to ‘Pending’. If so, then the function returns with an email not verified message.
- Checks if the user’s status is set to ‘Active’. If so, a JWT token is generated and returned.
- Otherwise an empty object is returned and an error is logged.
(This endpoint is called from the login() function in the front-end authentication service)
module.exports.register
This function takes in an object containing the user’s username, email, password, and a baseurl. It uses this data to create a new user in the DB. The function executes the following steps:
- Checks that the request body contains a username, password, and email. If not, the function returns with an error.
- Checks that the request body contains a baseurl. If not, it is set to the development url.
- Checks that the username has no special characters. If it does, then the function returns with an error.
- Creates a new User using the Mongoose model and the request body data. The setPassword() function in the User model is called with the password in order to save it to the DB.
- Attempts to save the new user. If there is an error, the function returns with the error.
- Sends a verification email by calling the sendVerificationEmail() function. If there is an error, the function returns with the error.
(This endpoint is called from the register() function in the front-end authentication service)
module.exports.verify
This function sets a user’s status to ‘Active’ once they click on the verification link sent to their email. It returns HTML for a success page to display to the user. The function executes the following steps:
- Checks that the request contains a username, email, and verification code. If not, the function returns with an error.
- Gets the user object from the database using the username and email. If the user does not exist, the function returns with an error.
- If the user object’s verification code matches the verification code in the request, the user’s status is set to ‘Active’ and the changes are saved to the DB.
- Returns the HTML success page stored in the ../views folder.
- Otherwise it returns a HTML error message.
(This endpoint is called from the generateActivationLink() function in the User model, which is called from the sendVerificationEmail() function in this controller)
module.exports.verifyOldAccount
This function verifies older accounts in the DB that did not have email verification upon registration. It returns either success or failure messages. The function executes the following steps:
- Checks that the request contains a username, email, and password. If not, the function returns with an error.
- Checks that the request body contains a baseurl. If not, it is set to the development url.
- Gets the user object from the database using the username. If the user does not exist, the function returns with an error.
- If the user’s status is set to ‘Active’ and an email exists in the user object, the function returns with an ‘already verified’ message. If the user does not have an email, the user’s status is set to ‘Pending’ and changes are saved to the DB. An error message is returned.
- Sends a verification email and saves the user’s new email by calling the sendVerificationEmail() function. If there is an error, the function returns with the error.
- Otherwise it returns with an unknown error.
(This endpoint is called from the verifyOldAccount() function in the front-end authentication service)
module.exports.resetPassword
This function resets the password for an existing user. It returns either success or failure messages. The function executes the following steps:
- Checks that the request body contains a username. If not, the function returns with an error.
- Checks that the request body contains a baseurl. If not, it is set to the development url.
- Gets the user object from the database using the username. If the user does not exist, the function returns with an error.
- Checks that the user has an email and that its status is set to ‘Active’. If not, the function returns with an error.
- Calls the generateResetPasswordLink() function in the User model to generate a password reset code. This function then calls the generateNewPassword() function in this authentication controller to get either the success or failure HTML.
- Attempts to save the user (the user’s password reset code was changed in the above functions). If there is an error, it is logged.
- Creates a mail object with this newly generated password link. Modifies the user’s email string to hide the address for privacy reasons (only for display, not saved).
- Sends the mail object to the user. If there is an error, the function returns with the error.
- Returns either a success or fail message.
(This endpoint is called from the resetPassword() function in the front-end authentication service)
module.exports.generateNewPassword
This function generates a new password for an existing user. It returns HTML for a success page to display to the user. The function executes the following steps:
- Checks that the request contains a username, email, and password reset code. If not, the function returns with an error.
- Gets the user object from the database using the username and email. If the user does not exist, the function returns with an error.
- Checks that the user’s status is set to ‘Active’. If not, the function returns with an error.
- Checks if the generated reset password code in the request matches the user’s reset password code. The generated code was saved to the user in a previous function, so this check makes sure the changes were actually saved to the DB. If not, the function returns with an error.
- Generates a new password by calling the generateNewPassword() function in the User model.
- Sets the new password to the user object by calling the setPassword() function in the User model.
- Attempts to save the new user. If there is an error, it is logged.
- Calls the sendEmail() function from the mail.js file to send an email to the user with the newly generated password.
- Returns a HTML success message.
(This endpoint is called from the generateResetPasswordLink() function in the User model, which is called from the resetPassword() function in this controller)
sendVerificationEmail()
This function sends a verification email to users after they register, or if they are older users who have not yet verified their account. It returns either a success or error message. The function executes the following steps:
- Gets the user object from the database using the username parameter. If the user does not exist, the function returns with an error.
- Calls the validPassword() function in the User model to check if the password parameter is valid. If not, the function returns with an error.
- Sets the user’s email to the email in the parameters. Calls the generateActivationLink() function in the User model to generate a validation link (which updates the verification code on the user object).
- Attempts to save the user’s new email. If there is an error, the function returns it.
- Creates a mail object with this newly generated verification link depending on the language preference in parameters (ga/en).
- Sends the mail object to the user. If there is an error, the function returns with the error.
- Returns either a success or fail message.
(Call from verifyOldAccount() and register() in this authentication controller)
Footnotes
-
Controller definition: https://www.w3schools.com/w3js/w3js_controllers.asp ↩
-
See Authentication Service documentation ↩
-
See Backend documentation ↩
-
See Model documentation ↩