@mdsbzalam
@mdsbzalam
Full Stack Developer
Auth0 Ambassador
@mdsbzalam
@mdsbzalam
1. Authentication & Authorization
2. JSON Web Token( JWT )
3. Securing Node.js API
4. Demo
@mdsbzalam
@mdsbzalam
@mdsbzalam
@mdsbzalam
source: dadario.com.br
@mdsbzalam
source: dadario.com.br
@mdsbzalam
@mdsbzalam
@mdsbzalam
@mdsbzalam
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
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
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:
@mdsbzalam
A finished token looks like [encoded header].[encoded payload].[signature] :
@mdsbzalam
@mdsbzalam
@mdsbzalam
@mdsbzalam
@mdsbzalam
@mdsbzalam
@mdsbzalam
@mdsbzalam
@mdsbzalam
$ 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
// jwt.sign(payload, secretOrPrivateKey, [options, callback])
jwt.sign({ foo: 'bar' }, privateKey, [options]);
// options
{
algorithm: 'RS256',
expiresIn: '1h' // 30s , 30*20, 2h
}
@mdsbzalam
// 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
const jwt = require('jsonwebtoken');
app.get('/api/public', function(req, res) {
res.json({
message: 'Hello from a public endpoint!'
});
});
@mdsbzalam
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
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
@mdsbzalam
@mdsbzalam
$ npm install --save express-jwt
$ npm install --save jwks-rsa
$ npm install --save express-jwt-authz
@mdsbzalam
// 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
// 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
@mdsbzalam
@mdsbzalam
Token Expiration in seconds.
@mdsbzalam
@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
General JWT Resources
JWT Handbook
Node.js API Authentication & Authorization
Node.js Authentication
@mdsbzalam
facebook.com/mdsbzalam
@mdsbzalam
@mdsbzalam
https://in.linkedin.com/in/mdsbzalam
mdsbzalam@gmail.com
@mdsbzalam
@mdsbzalam