A Complete guide to Deno and Oak with authentication using bcrypt and djwt, with mongoDB as database and Handlebars as template renderer
What is Deno?
A runtime for Javascript and Typescript.
Installing Deno 👷 :
A simple program 📝 :
Running above program ✈️ :
deno run deno_sample.js
Result :
Deno is cool
Deno is cool
Deno is cool
Deno is cool
What is Oak?
A middleware framework for Deno’s http server, including a router middleware.
Using Oak in our Deno application 📝 :
Running above program ✈️ ️:
deno run --allow-net oak_sample.js
Result :
Visit: http://localhost:8000/
Response: Welcome to / route
Visit: http://localhost:8000/anything
Response: Welcome to /anything route
Explanation 🔨 :
The Application
class has two methods: .use()
and .listen()
. We can use the .use()
method to add a middleware and the .listen()
method to start the server.
Using the Router Class, we can produce middleware which can be used with an application to enable routing based on the pathname of the request.
We are producing 2 middlewares (lines 3 to 10) and then using them in application (line 13).
In this case routing is enabled for paths GET /
and GET /anything
.
We are starting the server at port 8000
(in line 16).
What is bcrypt?
bcrypt is is a port from jBCrypt to TypeScript for use in Deno.
In simple terms, it helps us to hash passwords in Deno.
Using bcrypt in our Deno application 📝 :
Running above program ✈️ :
deno run --allow-net --unstable bcrypt_sample.js
Result :
$2a$10$AtHzqf4FxkOntit/zHRlzejt9pfNexYFLdZ2.ozk5KMM6A6n0t2m.
true
false
Explanation 🔨 :
We are hashing password test
(line 5) and then logging the hash to console (in line 6).
We are comparing hash with test
(line 8) (which gives true
as the hash was generated using test
)
We are comparing hash with wrong-test
(line 13) (which gives false
as the hash was generated using test
)
What is djwt?
djwt is a module which helps us to make JSON Web Tokens in deno.
Using djwt in our Deno application 📝 :
Running above program ✈️ :
deno run --allow-net djwt_sample.js
Result:
Run the program and visit: http://localhost:8000/newJwt
You should see a new JWT (something like) : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ0ZWQiLCJleHAiOjE1OTI5NzM1ODM0Nzl9.gBBXK6bCXHhsN5I7OthcmiH5kjQW77rfeLFTrtFX1lc
Now visit http://localhost:8000/validate
(within 60 seconds of making the above request) :
You should see : Valid Jwt
Now visit http://localhost:8000/validate
( after 60 seconds have passed ):
You should see : Invalid Jwt
Explanation 🔨 :
On requesting, http://localhost:8000/newJwt
server makes a new JSON web token ( which expires after 60,000 ms ) (line 20) and set token
to the newly created JWT in cookies
(line 22) and also sets response body to the newly created JWT (line 21).
On requesting, http://localhost:8000/validate
, if there is token
in cookies (line 25,26), server checks if the token is a valid JSON web token (line 27) and correspondingly responds with proper message ( “Valid Jwt” or “Invalid Jwt”
) (line 28),
else it reponds with “No token in cookies”
(line 31).
What is deno_mongo?
deno_mongo is a MongoDB database driver for Deno.
Using deno_mongo in our Deno application 📝 :
Running above program ✈️ :
deno run --allow-net --allow-read --allow-write --allow-plugin --unstable deno_mongo_sample.js
Result :
What is Handlebars?
Handlebars template render for Deno
Using Handlebars in our Deno application 📝 :
Make a folder like this :
/views
/layouts
/main.hbs
/partials
/foot.hbs
/head.hbs
/home.hbs
/index.js
Add your footer here:
Add your header/navbar here
We are rendering home.hbs when GET / route is requested:
Running ✈️ :
deno run — allow-net — allow-read index.js
Result:
Visit: http://localhost:8000/
Response: Welcome Cliffjumper
Let’s make a simple web app :
Cybertron
What will it do:
A prime (user) can enter cybertron (login) using a username and a password. Also a transformer (user) can also register himself (signup) as a prime on cybertron.
Only primes who have entered cybertron (logged in users) can create new Autobots and Decepticons.
Any transformer (user) can see all the Autobots and Decepticons created by the primes.
Overview:
Routes:
GET /
:
if prime (user) is logged in,
Show the
logout
button, which takes us to/logout
route
Show Create a Transformer form, which can be used to add a transformer.
All the Autobots in database.
All the Decepticons in database.
else,
Show Register form (signup) which can be used to register (signup).
Show Enter form, which can be used to enter Cybertron (login).
All the Autobots in database.
All the Decepticons in database.
POST /
:
If prime (user) is logged in,
If a transformer already exists with the name as name in the POST request,
Redirect back to/
else,
Add transformer to appropriate collection
Redirect back to/
else
Redirect back to
/
POST /signup :
If prime (user) is logged in,
Redirect back to
/
else,
If prime (user) already exists with username as in body of POST request,
Redirect back to/
else,
Hash the password in POST request using bcrypt and add the prime to primes collection
Redirect back to/
POST /login :
If prime (user) is logged in,
Redirect back to
/
else,
If prime (user) exists in database (username and password match),
Settoken
in cookies : New JWT (using djwt)
Redirect back to/
else,
Redirect back to/
GET /logout :
If prime (user) is logged in,
Set
token
in cookies : “”
Redirect back to/
else,
Redirect back to
/
Make a folder structure like this:
/controllers
/authControllers.js
/transformerControllers.js
/routes
/routes.js
/utils
/handlebars.js
/jwt.js
/parseBody.js
/validate.js
/views
/layouts
/main.hbs
/partials
/foot.hbs
/head.hbs
/list.hbs
/db.js
/index.js
db.js
: Database stuff
A database cybertron
with collections autobots
, decepticons
, primes.
/utils/parseBody.js
: A function to parse body of POST request
/utils/jwt.js
/utils/handlebars.js
/utils/validate.js
A function validate
which gets token from cookies
and checks it’s validity
.
If token
is valid
, (prime [user] is logged in) sets request.auth = true
Our application will use it for every request.
/controllers/authControllers.js
If request.auth == true
, prime (user) is logged in.
/controllers/transformerControllers.js
Using message
in cookies
to set proper message and later use that message
on GET /
route.
Also whenever GET /
route is requested, if there is message
in cookies, we are setting message
in cookies to “”
as that message is not needed anymore.
When rendering HTML for GET /
route, we are passing autobots
, decepticons,
request
, message.
/views/layouts/main.hbs
/views/partials/foot.hbs
/views/partials/head.hbs
head for GET /
route.
While rendering,
If
message
,
displaymessage
If
request.auth
, i.e. prime (user) is logged in,
displaylogout
andCreate Transformer
else,
displayregister
andenter form
/views/list.hbs
Display all autobots
and decepticons
in database.
/routes/routes.js
Using the Router Class, we are produceing middlewares which are used with application to enable routing to GET /
, POST /
, POST /signup
, POST /login
, GET /logout
.
/index.js
Application uses validate
: [middleware
to check if prime (user) is logged in]
Application uses all routes
in /routes/routes.js
Running:
deno run — allow-net — allow-read — allow-write — allow-plugin — unstable index.js