Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JWT authentication with Deno

How to create and validate JSON Web Token in Deno?

I am new to the Deno runtime, so it would be helpful to have a sample to get started with JWT in Deno.

like image 491
Laura Nutt Avatar asked Oct 23 '20 06:10

Laura Nutt


1 Answers

Here is a short demonstration that shows how to create a JWT with a HS256 signature and how to verify it and extract the payload.

jwtdemo.ts (based on Version 2.4 of djwt):

import { create, verify , getNumericDate, Payload, Header} from "https://deno.land/x/[email protected]/mod.ts";

const encoder = new TextEncoder()
var keyBuf = encoder.encode("mySuperSecret");

var key = await crypto.subtle.importKey(
  "raw",
  keyBuf,
  {name: "HMAC", hash: "SHA-256"},
  true,
  ["sign", "verify"],
)

const payload: Payload = {
  iss: "deno-demo",
  exp: getNumericDate(300), // expires in 5 min.
};

const algorithm = "HS256"

const header: Header = {
  alg: algorithm,
  typ: "JWT",
  foo: "bar"  // custom header
};

const jwt = await create(header, payload, key)

console.log(jwt);

// create a different key to test the verifcation
/*keyBuf = encoder.encode("TheWrongSecret");
key = await crypto.subtle.importKey(
  "raw",
  keyBuf,
  {name: "HMAC", hash: "SHA-256"},
  true,
  ["sign", "verify"],
)
*/

try {
  const payload = await verify(jwt, key); 
    console.log("JWT is valid");
    console.log(payload);
}
catch(_e){
  const e:Error= _e;
  console.log(e.message);
}

The current version of djwt now utilizes the Web Crypto API which is available since Deno 1.11. The functions create and verify need the key-parameter to be provided as an CryptoKey object, so even for HS256 you can't pass a simple string anymore but need to create a proper key object as seen in the first lines of the code above.

The helper method getNumericDate(exp) automatically sets a correct Unix timestamp and adds the number of seconds given as an argument to the current time or uses the given date argument directly.

You can run the above demo directly and all imported modules will be downloaded automatically:

deno run jwtdemo.ts

The result is:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImZvbyI6ImJhciJ9.eyJpc3MiOiJkZW5vLWRlbW8iLCJleHAiOjE2MzMzNzUyODl9.FBYgDrpG9RXJSfgme-430UyFLvdNTNliYTKGiWajksQ
JWT is valid
{ iss: "deno-demo", exp: 1633375289 }

or, in case of a wrong signature (uncomment the code block with the wrong secret to test this):

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImZvbyI6ImJhciJ9.eyJpc3MiOiJkZW5vLWRlbW8iLCJleHAiOjE2MzMzNzU0MDd9.F3szgyrTJSQG3m1a82OJkKqKIDD32Q21ZchAVAj74bk
The jwt's signature does not match the verification signature.

A notable difference to JWT creation in node.js is, that we have predefined interfaces Header and Payload here instead of simple JSON, and values are checked.

When I set

const algorithm = "XS256"   // instead of "HS256"

the check of the algorithm will fail and the program doesn't start:

Check file:///C:/Users/jps/source/deno/jwtdemoV19.ts
error: TS2322 [ERROR]: Type '"XS256"' is not assignable to type 'Algorithm'.
  alg: algorithm,
  ~~~
    at file:///C:/Users/jps/source/deno/jwtdemoV19.ts:8:3

    The expected type comes from property 'alg' which is declared here on type 'Header'
      alg: Algorithm;
      ~~~
        at https://deno.land/x/[email protected]/mod.ts:36:3

TS2345 [ERROR]: Argument of type '"XS256"' is not assignable to parameter of type 'AlgorithmInput'.
        const payload = await verify(jwt,  key, algorithm)
                                                ~~~~~~~~~
    at file:///C:/Users/jps/source/deno/jwtdemoV19.ts:26:42

Found 2 errors.

The sample code utilises djwt version 2.4, which currently supports HSxxx, RSxxx, PSxxx and ESxxx (with xxx one of 256, 384, 512) signature algorithms. More algorithms will be added in future, depending on the availability of support in the deno crypto modules.

Read this answer to see how to verify an RS256 signed token.

Note: This answer has been rewritten to cover the breaking changes of the djwt api in version 2.4. The old version of this post was based on djwt v1.9

like image 75
jps Avatar answered Oct 17 '22 20:10

jps