The purpose of this project is to have an easily usable authentication microservice that one could "plug and play" into their existing API or gateway. This project is be 100% working out of the box. However, it is also meant to be a starting point for those who want a more customized authentication service. The microservice is also meant to be used how you would like it to be used, meaning certain pages (login, register, password reset) are provided but are by no means required to be used. If you would like to customize the pages or use another service for the pages, it is encouraged.
NOTE: Passwords are hashed using bcrypt
- Simple login page
- Simple registration page
- Password reset functionality
- Delete account
- Uses MongoDB as datastore
- Dockerfile and Docker-Compose configuration
- Encrypt everything in database (User collection/table) at rest
- Allow for interchangeable databases with just specifying an environment variable (currently only MongoDB will be supported out of the box)
- Add more security features to prevent against spamming (brute-force) and DOS attacks
- Verify email
- Flags for using sessions and bearer tokens
All optional fields are marked with '(optional)' in front of them. Do not include '(optional)' in actual request.
Also, note that the message is not always ok
, even if the error
field is not included
Accepts: application/x-www-form-urlencoded, application/json
email
: String (the email associated with the user)password
: String (the password from the user)- (optional)
firstname
: String - (optional)
lastname
: String - (optional)
username
: String (a non-unique username)
Example request:
{
"email": "john@smith.com",
"password": "password",
"username": "jsmith192"
}
Returns: application/json
message
: String (ok
if everything went alright)error
: (only included when error occurred)
Accepts: application/x-www-form-urlencoded, application/json
email
: String (the email associated with the user)password
: String (the password from the user)
Returns: application/json
message
: String (ok
if everything went alright)token
: String (Only included when login is successful)user
: an object representing the logged in user
Example response:
{
"message": "ok",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVjMWFkNjQ1MjMwNWJjMTJlY2YyNGE0MiIsImlhdCI6MTU0NTI2MjczMywiZXhwIjoxNTQ1NDM1NTMzfQ.RcJv26xteu-SsdiJ572gb4y7GAJ9Jo9dAlUiwvi7oj8"
}
Accepts: application/x-www-form-urlencoded, application/json, (Authorization header to be added as option instead of the other two)
jwtToken
: String (the token received from /login)
Returns: application/json
message
: String
Accepts: application/x-www-form-urlencoded, application/json
email
: String (the user email that is requesting the reset)
Returns: application/json
message
: String (ok
if everything went alright)error
: (only included when error occurred)
:token is the token that was generated by /forgot
. The token is already included in the link that is emailed to the user. This is NOT the JWT from /login
Accepts: application/x-www-form-urlencoded, application/json
password
: String (the new user password)
Returns: application/json
message
: String (ok
if everything went alright)error
: (only included when error occurred)
Currently, logout only deletes the cookie with the token, if cookies are enabled.
Accepts: application/x-www-form-urlencoded, application/json
jwtToken
: String (the token received from /login) - not needed if cookies enabled
Returns: application/json
message
: String
Accepts: application/x-www-form-urlencoded, application/json
jwtToken
: String (the token received from /login)email
: String (the email of the user that is to be deleted. This email must match that of the user associated with the jwtToken)
Returns: application/json
message
: Stringerror
: (only included when error occurred)
Returns HTML registration page
Returns HTML login page
Returns HTML forgot password page
Returns HTML password reset page
There are a couple locations where you are able to easily change some of the configurations. The .env
file contains environment variables that pertain to service configurations and private data. You should modify the variables to your uses.
Currently, the email information is only used for password reset related functionality. However, an optional feature to send a verification email will also be using the email information in a future release. As you might notice, email credentials are in the .env
file and email service configuration is in the config.js
file. You can find the SMTP information on your providers site or here: https://www.arclab.com/en/kb/email/list-of-smtp-and-pop3-servers-mailserver-list.html
# All variables defined here will not overwrite variables currently defined in environment
# Backend services
HOST='localhost'
PORT=3000
AUTH_PATH='/' # used for the optional pages to direct to correct endpoint location (i.e. '/auth/' or '/auth/jwt/')
TOKEN_SECRET='secret' # Change this to whatever you would like your token secret to be
TOKEN_EXPR='2d' # Token Expiration Length. Eg: 60, "2 days", "10h", "7d". A numeric value is interpreted as a seconds count.
# If you use a string be sure you provide the time units (days, hours, etc), otherwise milliseconds unit is used by default ("120" is equal to "120ms").
COOKIE_SECRET='secret'
COOKIE_EXPR=172800000 # The number of milliseconds that the cookie should last. Unlike the TOKEN_EXPR variable, this must be a number. It is currently set to 2 days
EMAIL_USER='username' # the username for the SMTP/email account you are using for password reset
EMAIL_PASS='password' # password for the account mentioned above
# Database
DB_HOST='localhost'
DB_PORT=27017
DB_NAME='JWTService'
It is recommended that the
TOKEN_EXPR
and theCOOKIE_EXPR
are set for the same time period.
The config.js
contains some necessary/optional configurations so that you will not have to go digging through the code to fix some things. You might still want to go digging to customize as you see fit.
const databaseConnectionOptions = {
useNewUrlParser: true,
reconnectTries: Number.MAX_VALUE,
reconnectInterval: 500
}
function databaseConnectionError (error) {
if (error) {
console.log('Failed to first attempt to connect to database:', error)
}
}
// Used to send emails for password reset
var smtpTransport = nodemailer.createTransport({
host: 'smtp.sendgrid.net', // change host to your email or SMTP host
port: 587, // unsecure SMTP port for SendGrid. Change to the proper port for your service
secure: false, // Change if sending securely
auth: {
user: process.env.EMAIL_USER,
pass: process.env.EMAIL_PASS
}
})
var passwordResetEmail = 'noreply@passwordreset.com' // Your 'from' email for password reset
// Only used when the '-c' (enable cookie use) is passed on service startup
var cookieOptions = {
signed: true,
maxAge: process.env.COOKIE_EXPR,
httpOnly: true
}
{
email: {
type: String,
unique: true,
required: true,
trim: true
},
username: {
type: String,
unique: true,
required: false,
trim: true
},
firstname: {
type: String,
required: false,
trim: true
},
lastname: {
type: String,
required: false,
trim: true
},
password: {
type: String,
required: true
},
dateCreated: {
type: Date,
required: false,
default: Date.now
},
passwordResetToken: String,
passwordResetExpires: Date,
verified: {
type: Boolean,
default: false
}
}
Getting started is quite simple using the following steps:
Clone the repository to your desired location:
git clone https://github.com/tmcdo1/auth-jwt-service.git
Install all the required packages:
npm install
Run for development purposes (uses nodemon
):
npm start
Run for production purposes:
npm run prod
This does not include database setup which is required to use. Follow the MongoDB installation manual: https://docs.mongodb.com/manual/installation/
If running without Docker, make sure to change the
DB_HOST
variable in the .env file tolocalhost
or the server where your database is located.
A Dockerfile
is provided for this service, as well as a docker-compose.yml
. The Docker-Compose configuration includes a MongoDB container set to use /data/db
as a volume.
To run the service, start Docker on your machine. Then, just type docker-compose up
and everything will be running properly.
If the -c
or --cookies
option is passed when running the service (add or remove from the start or prod script in the package.json
file), a signed cookie will be set to store the user's token on the /login
POST endpoint. The cookie will then be used to authenticate the user on the /authenticate
POST endpoint.
Ex: node index.js -c
From your perspective, using cookies is an easy way to get started, as you will not have to write any code to store the token for the user.