A Complete guide to Deno and Oak with authentication using bcrypt and djwt, with mongoDB as database and Handlebars as template renderer

CHETAN GARG
Nybles
Published in
5 min readJun 26, 2020

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),
Set token 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,
display message

If request.auth, i.e. prime (user) is logged in,
display logout and Create Transformer

else,
display register and enter 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

Thanks 😃

--

--