- Fork and clone this repository to your
Development
folder.
After forking the repository, you will find a fully functional url shortener!
The goal is to prevent any unauthorized user from using our service.
- Install
bcrypt
and require it inusers.controllers
. - In
users.controllers
, implement the following inside thesignup
controller:- Hash the password with
10
salt rounds and overwritereq.body.password
with the new, hashed password. - Pass the body of the request to
User.create
. - Change the response status to
201
and end it with a message.
- Hash the password with
- Test your route in Postman.
Generate and return a token in users.controllers
's signup
function.
- Install
jsonwebtoken
. - Require
jwt
fromjsonwebtoken
at the top ofusers.controllers
. - In
users.controllers
, create a function calledgenerateToken
that takesuser
as an argument. - In this function, create an object called
payload
and pass it the user'susername
and_id
that's coming fromuser
. - After creating your
payload
object, calljwt.sign()
and pass it two arguments:payload
JWT_SECRET
- Add an object as a third parameter to the
jwt.sign()
function that has aexpiresIn
key and its value is the token's duration from theJWT_TOKEN_EXP
variable. - In the
signup
function, after creating the user callgenerateToken
and pass it the new user. - Save the returned value in a variable called
token
and send it as a response (json object should have a key of token with an encoded string as its value). - Test your route in Postman.
- Install
passport
andpassport-local
. - Require
passport
inapp.js
. - Call the
app.use
method and pass itpassport.initialize()
.
- In
middleware
, create a file calledpassport.js
. - Require
LocalStrategy
frompassport-local
. - Create a variable called
localStrategy
that's equal to aLocalStrategy
instance. - Pass
LocalStrategy
an asynchronous function as an argument. This function receives three parameters:username
,password
anddone
. - Add a
try catch
statement in the function. In thecatch
block, calldone
and pass iterror
. - Look for a
user
in theUser
model that has theusername
that's passed to the local strategy. Save it in a variable calleduser
. - Don't forget to import
User
. - Import
bcrypt
. - If
user
exists, callbcrypt.compare()
and pass itpassword
anduser.password
for comparison. - Save the returned value in a variable called
passwordsMatch
. - If
user
doesn't exist, setpasswordsMatch
tofalse
. - If
passwordsMatch
istrue
, returndone()
and pass it two arguments,null
anduser
. - Else, return
done()
and pass it two arguments,null
andfalse
. - In
app.js
, require thelocalStrategy
instance that we just created. - Under the passport initialization, call
passport.use()
and pass itlocalStrategy
. - In the
/signin
route, callpassport.authenticate()
and pass it "local
" and{ session: false }
as arguments.
Generate a token a token in users.controllers
's signin
function.
- In the
signin
function, callgenerateToken
and pass it the user object obtained from passport middleware. - Save the returned value in a variable called
token
and send it as a response (json object should have a key of token with an encoded string as its value). - Test your route in Postman.
- Start with installing the
JWT strategy
. - In
middleware/passport.js
requireJWTStrategy
. - We will create a JWT strategy instance, which takes two arguments, an
options
object and a callback function. - Tokens can be extracted from the request in many ways. We will pass our token in the request's authorization header with the scheme bearer. We need to require
fromAuthHeaderAsBearerToken
. - Now we will pass this function to our
options
object. Also, we will pass ourJWT_SECRET
for the keysecretOrKey
. - Now the second argument, an asynchronous callback function, takes two arguments, the token's payload and done function. So the JWT strategy decodes the token and passes the payload as an argument.
- Check if the token is expired or not by comparing the expiration date to the date right now. If the token is expired, call
done
and pass itnull
andfalse
as arguments, which will throw a401
error. - If the token is not expired, we will find the
user
with the ID saved in the token. You can usefindOne
and pass it theusername
. Then we will pass the founduser
todone
. If nouser
is found, it will throw a401
error. - Let's initialize our strategy in
app.js
. RequirejwtStrategy
and pass it topassport.use()
.
- In
urls.routes
we will restrict theshorten
endpoint to only allow authenticated users to create shortened urls. Start by requiringpassport
inusers.routes
- In the
/shorten/:userId
route, callpassport.authenticate()
and pass it "jwt
" and{ session: false }
as arguments. - Remove the
/:userId
param from the route. - In the
urls.controllers
, modify theshorten
function to usereq.user
instead of the route param. - Test your endpoint in Postman.
- In the
urls.routes
, callpassport.authenticate()
and pass it "jwt
" and{ session: false }
as arguments in the delete endpoint. - In the
urls.controllers
's deleteUrl function, add a condition that will compare the ids of the user making the request, and the id of the user that created the instance. In the condition, only allow the user who created the url to delete the url. - Return an authorized status and message to the user if they are attempting to delete the url and if they are not the creator!