@mdsbzalam

Securing Node.js APIs using JWT

@mdsbzalam

About Me

Md. Shahbaz Alam

Full Stack Developer

Auth0 Ambassador

 

 

@mdsbzalam

 

@mdsbzalam

Agenda

1. Authentication & Authorization

2. JSON Web Token( JWT )

3. Securing Node.js API

4. Demo

@mdsbzalam

Authentication & Authorization

@mdsbzalam

Authentication & Authorization

Difference

@mdsbzalam

Difference

Authentication & Authorization

@mdsbzalam

Authentication & Authorization

source: dadario.com.br

@mdsbzalam

Authentication & Authorization

source: dadario.com.br

@mdsbzalam

JSON Web Token

@mdsbzalam

JWT

What is JSON Web Tokens?

- A way to encode information

- Securely communicate JSON Objects

- Secret-based Verification

- Consists of a header, payload and signature

- Self-contained

@mdsbzalam

JWT

JSON Web Token

@mdsbzalam

JWT

The JWT Header

The header is a JSON Object usually consisting of the type( typ ) , which is JWT, and the algorithm used for encrypting the JWT (alg ):

{
  "alg": "HS256",
  "typ": "JWT"
}

@mdsbzalam

JWT

The JWT Payload

The Payload is a JSON object that consists of user defined attributes ( called public claims ) . Some attributes are defined in the standard ( these are called reserved claims ).

{
    // reserved claim
    "iss": "https://myapi.com", 
    // public claim
    "user": "mdsbzalam" 
}

@mdsbzalam

JWT

The JWT Signature

The Signature is the encoded header and payload, signed with a secret.

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret
)

This accomplishes several tasks at once, including:

  • Proves the identity of the sender
  • Ensures the message has not changed

@mdsbzalam

JWT

The JWT Token

A finished token looks like [encoded header].[encoded payload].[signature] :

@mdsbzalam

JWT

The JWT Token

@mdsbzalam

How an application uses JWT to verify the authenticity of a user.

@mdsbzalam

@mdsbzalam

@mdsbzalam

Securing Node.js API

@mdsbzalam

@mdsbzalam

  • GET /api/public: available for non-authenticated requests

 

  • GET /api/private: available for authenticated requests containing an Access Token

API endpoint

@mdsbzalam

We will see two different approach of securing our API using JWT

  • Using node-jsonwebtoken

  • Auth0's way of securing

@mdsbzalam

node-jsonwebtoken

$ npm install jsonwebtoken
// Synchronous Sign with default (HMAC SHA256)

var jwt = require('jsonwebtoken');
var token = jwt.sign({ foo: 'bar' }, 'shhhhh');

// Synchronous Sign with RSA SHA256

// sign with RSA SHA256
var privateKey = fs.readFileSync('private.key');
var token = jwt.sign({ foo: 'bar' }, privateKey, { algorithm: 'RS256'});


// Sign asynchronously
jwt.sign({ foo: 'bar' }, privateKey, { algorithm: 'RS256' }, function(err, token) {
  console.log(token);
});

@mdsbzalam

node-jsonwebtoken

// jwt.sign(payload, secretOrPrivateKey, [options, callback])

jwt.sign({ foo: 'bar' }, privateKey, [options]);

// options
{
    algorithm: 'RS256',
    expiresIn: '1h'  // 30s , 30*20, 2h
}

@mdsbzalam

node-jsonwebtoken

// jwt.verify(token, secretOrPublicKey, [options, callback])

// verify a token symmetric - synchronous
var decoded = jwt.verify(token, 'shhhhh');
console.log(decoded.foo) // bar

// invalid token - synchronous
try {
  var decoded = jwt.verify(token, 'wrong-secret');
} catch(err) {
  // err
}

@mdsbzalam

node-jsonwebtoken

const jwt = require('jsonwebtoken');

app.get('/api/public', function(req, res) {
  res.json({
    message: 'Hello from a public endpoint!'
  });
});

@mdsbzalam

node-jsonwebtoken

const jwt = require('jsonwebtoken');

app.get('/api/token', function(req, res) {
    res.json({
      token: jwt.sign(
            { 
              conference: 'Byteconf JS 2019',
              speaker: 'Md. Shahbaz Alam', 
              talk: 'Securing Node.js API using JWT', 
              social: '@mdsbzalam' 
            }, 'secret')
    });
});

@mdsbzalam

node-jsonwebtoken

const jwt = require('jsonwebtoken');

app.get('/api/private', function(req, res) {
  res.json({
    message: 'Hello from a private endpoint!',
    data: jwt.verify('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJjb25mZXJlbmNlIjoiQnl0ZWNvbmYgSlMgMjAxOSIsInNwZWFrZXIiO
iJNZC4gU2hhaGJheiBBbGFtIiwidGFsayI6IlNlY3VyaW5nIE5vZGUuanM
gQVBJIHVzaW5nIEpXVCIsInNvY2lhbCI6IkBtZHNiemFsYW0iLCJpYXQiO
jE1NTI2NDYwMTN9.schVN33Z6zelvqEOEHxg8j
BYEl84iVCab7tS3qsBcjY', 'secret')
  });
});

@mdsbzalam

node-jsonwebtoken

@mdsbzalam

node-jsonwebtoken

@mdsbzalam

Auth0's approach

$ npm install --save express-jwt 
$ npm install --save jwks-rsa 
$ npm install --save express-jwt-authz

Install dependencies

@mdsbzalam

Auth0's approach

Configure the middleware

// server.js

const jwt = require('express-jwt');
const jwtAuthz = require('express-jwt-authz');
const jwksRsa = require('jwks-rsa');

const checkJwt = jwt({
  // Dynamically provide a signing key
  // based on the kid in the header and 
  // the signing keys provided by the JWKS endpoint.
  secret: jwksRsa.expressJwtSecret({
    cache: true,
    rateLimit: true,
    jwksRequestsPerMinute: 5,
    jwksUri: `https://YOUR_DOMAIN/.well-known/jwks.json`
  }),

  // Validate the audience and the issuer.
  audience: 'YOUR_API_IDENTIFIER',
  issuer: `https://YOUR_DOMAIN/`,
  algorithms: ['RS256']
});

@mdsbzalam

Auth0's approach

Configure the middleware

// server.js

// This route doesn't need authentication
app.get('/api/public', function(req, res) {
  res.json({
    message: 'Hello from a public endpoint! You don\'t need to be authenticated to see this.'
  });
});

// This route need authentication
app.get('/api/private', checkJwt, function(req, res) {
  res.json({
    message: 'Hello from a private endpoint! You need to be authenticated to see this.'
  });
});

To protect an individual route that requires a valid JWT, configure the route with the checkJwt express-jwt middleware.

@mdsbzalam

source: auth0.com

* Configure Auth0 APIs

@mdsbzalam

@mdsbzalam

Token Expiration in seconds.

@mdsbzalam

Demo

@mdsbzalam

/api/public

{
    "message": "Hello from a public endpoint! You don't need to be authenticated to see this."
}

@mdsbzalam

/api/token

@mdsbzalam

{
    "message": "Token.",
    "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IlJqbEVPREpE
TjBZd05ESTJNa1pGUTBSR1FrVkdOakkxUlRWQk1ETXhRak01TlRNM1JFRXdPUSJ9.eyJpc3MiOiJodH
RwczovL3NoYWhiYXoxNy5hdXRoMC5jb20vIiwic3ViIjoiMHFqR1hWYmlCMFllY0U1aE1relp5d2
14dE1JNkZvSVFAY2xpZW50cyIsImF1ZCI6ImZyaWVuZCIsImlhdCI6MTU1MjY0Mzc1MCwiZXhwIj
oxNTUyNzMwMTUwLCJhenAiOiIwcWpHWFZiaUIwWWVjRTVoTWt6Wnl3bXh0TUk2Rm9JUSIsInNjb3
BlIjoicmVhZDptZXNzYWdlcyIsImd0eSI6ImNsaWVudC1jcmVkZW50aWFscyJ9.JQsbHuU7XTi
VdhdvlN5amHigxZIrtlD1NAwNaXG8M1uIUQcZpSyV7j_DvUaJJiLuihipVqwz7Et9sEMgRpw
IqBiDqN5bsPDa4BZHlnnmv8F9QG87jpbKDtVRfv56r5C0CFB8B5uf5AV1hJiw1ljpoOWdZCZG-
j5fGWzag76QTu8MsUtRFHo0DfkiZvcMuw6HwLH99DcR1UDXBtEQf0xHKhRCnuHlMVap-F9
hl2p0eGPS5vvo90ZDSfY6_LCBTaKPjFwGpI234lsjDj4pC5KC93dRxgpDpgtpSgyhml
sjzjCO4zdLxh9bGkp9VBlqR7Y6HUxPO0MGjHioTuc6ynzZfg"
}

@mdsbzalam

/api/private

@mdsbzalam

/api/private

{
    "message": "Hello from a private endpoint! You need to be authenticated to see this."
}

@mdsbzalam

Resources

General JWT Resources

jwt.io 

JWT Handbook

http://bit.ly/jwt-book

Node.js API Authentication & Authorization

https://auth0.com/docs/quickstart/backend/nodejs

node-jsonwebtoken

  

@mdsbzalam

Connect with me

Facebook

facebook.com/mdsbzalam

Twitter

@mdsbzalam

Instagram

@mdsbzalam

LinkedIn

https://in.linkedin.com/in/mdsbzalam

E-mail

mdsbzalam@gmail.com

@mdsbzalam

Slide

@mdsbzalam

Thank you

@mdsbzalam

Byteconf Javascript 2019

By Mohammad Shahbaz Alam

Byteconf Javascript 2019

Securing Node.js APIs using JWT

  • 815