Loading

Deno - JWT Authentication

Deno - JWT Authentication

Hi friends, hope you all are safe and sound.

Today we are going to discuss JWT authentication process in DENO. Till now we have learned the following in Deno

Now in this article we will see how we achieve JWT( JSON Web Token) in DENO using djwt.

Generate & Validate Token in Deno

For this we have created token.ts in this file you can see token realted methods like generate and validate.

import { validateJwt, parseAndDecode, validateJwtObject } from "https://deno.land/x/djwt/validate.ts";
import { makeJwt, setExpiration, Jose, Payload } from "https://deno.land/x/djwt/create.ts";

const key = "your-secret";

const header: Jose = {
  alg: "HS256",
  typ: "JWT",
};

export default{
    async generateToken(userID:any) {
      const payload: Payload = {
        uid: userID,
        exp: setExpiration(new Date().getTime() + 60000 * 60),
      };
      return makeJwt({ header, payload, key })
    },

    async validateToken(jwt:any) {
        return await validateJwt({jwt, key, algorithm: "HS256" });
    },

    fetchUserId(token: string): any {
      return validateJwtObject(parseAndDecode(token)).payload;
    }
}

Now if we give it a shape we can use the token in below example. Here we will take bellow ts files for this example.

  • app.ts
  • controller.ts

To support the above, we need below files under utils folder

  • authMiddleware.ts
  • token.ts

Application and Routes

First we will prepare the app.ts file where we will start the game. Loading all important modules. On the same page we have declare the routing options. We can create a separate routing page but for now let it be simple.

import { Application } from 'https://deno.land/x/oak/mod.ts';
import { Router } from 'https://deno.land/x/oak/mod.ts';
import { authMiddleware } from "./utils/authMiddleware.ts";
import { loginEmployee, getEmployees, logoutEmployee } from './controller.ts';

const PORT = 8000;
const app = new Application();
const router = new Router();

router
    .post('/login', loginEmployee)
    .get('/employees', authMiddleware, getEmployees)
    .get('/logout', authMiddleware, logoutEmployee)
;

app.use(router.routes());
app.use(router.allowedMethods());

console.log("Server is up and running in port:", PORT);  
app.listen({port: PORT});

Controller

Now after creating the app.ts its time to prepare the controller.ts.

  import db from "./database/mongodb.ts";
  import hash from './utils/hash.ts';
  import token from './utils/token.ts';

  const empCollection = db.collection("employees");

  const getEmployees = async (ctx: any) => { 
    const employees = await empCollection.find();
    ctx.response.body = employees;
  };

  const loginEmployee = async (ctx: any) => {

    const array = ['email', 'password'];
    const emp_val = await validation.validate(ctx, array);

    if( !emp_val) {
      ctx.response.status = 422;
      ctx.response.body = { error: "Invalid username/password" };
      return;
    }

    const emp:any = await empCollection.findOne({email: emp_val.email});


    if( !emp ) {
      ctx.response.status = 422;
      ctx.response.body = { error: "Invalid username/password" };   
      return; 
    }  
    let passFlag = false;
    passFlag =  await hash.verify(emp.password, emp_val.password);

    if( !passFlag ) {
      ctx.response.status = 422;
      ctx.response.body = { error: "Invalid username/password" };
      return;
    }

    const jwt = await token.generateToken(emp._id.$oid);
    ctx.response.body = jwt;
    ctx.cookies.set('jwt', jwt);
    ctx.response.status = 201

  };


  const logoutEmployee = async (ctx: any) => {
    ctx.cookies.delete('jwt');
    ctx.response.body = { success: "Successfully Logout." };
  };

  export { getEmployees, loginEmployee, logoutEmployee }

Middleware

We need to create few files to support the controller. First we need to think a middleware which authenticate the request.

import { Context } from "https://deno.land/x/oak/mod.ts";
import token from '../utils/token.ts';
import db from "../database/mongodb.ts";

const empCollection = db.collection("employees");

const authMiddleware = async (ctx: Context, next: Function) => {
  if (!ctx.state.currentUser) {
    const jwt = ctx.cookies.get('jwt');
    if (jwt) {
        const isTokenValid = await token.validateToken(jwt);
        if(!isTokenValid) {
            ctx.cookies.delete('jwt');
            ctx.response.status = 401;
            ctx.response.body = {error: "Unauthorized2"};
            return;
        }
        const payload = token.fetchUserId(jwt);
        if(payload) {
            const uid:string = String(payload.uid);
            const emp = await empCollection.findOne({_id: { $oid: uid }});
            ctx.state.currentUser = emp;
        }

    } else {
        ctx.state.currentUser = null;
        ctx.response.status = 401;
        ctx.response.body = {error: "Unauthorized3"};
        return;
    }
  }
  await next();
}

export {authMiddleware};  

DB Connection

Finally we need the mongodb.ts. Lets see.

import { MongoClient } from "https://deno.land/x/mongo/mod.ts";

const DB_URL = "mongodb://localhost:27017"
const mongo_client = new MongoClient();
mongo_client.connectWithUri(DB_URL);

const db = mongo_client.database('employees_db');

export default db;

Summary

So by the above example we are now clearly understand how JWT token are created in Deno and how they are validated and can use in the middleware.

Please leave a comment at info@codinghub.net and share this article as much as you can. Thank you very much!

We are on Facebook, Twitter, LinkedIn, Medium, Quora, Instagram, etc.

By the way, want to learn more about Deno? Just check out the official Deno documentation.

Related Articles