Categories
Nodejs

Add Token Authentication to Our Fastify App with fastify-jwt

With the fastify-jwt library, we can add basic authentication to our Fastify app quickly.

In this article, we’ll look at how to use the library to add authentication to our Fastify app.

Installation

We can install the package by running:

npm i fastify-jwt

Issuing Tokens

We can issue tokens by using thee fastify.jwt.sign method.

For example, we can write:

const fastify = require('fastify')({
  logger: true
})
fastify.register(require('fastify-jwt'), {
  secret: 'secret'
})

fastify.post('/signup', (req, reply) => {
  const token = fastify.jwt.sign({ foo: 'bar' })
  reply.send({ token })
})

fastify.listen(3000, '0.0.0.0', function (err, address) {
  if (err) {
    fastify.log.error(err)
    process.exit(1)
  }
  fastify.log.info(`server listening on ${address}`)
})

We just call the method with the object we want as the payload to return a token.

Verify Token

We can verify the token with the jwtVerify method.

For example, we can write:

const fastify = require('fastify')({
  logger: true
})
fastify.register(require('fastify-jwt'), {
  secret: 'secret'
})

fastify.decorate("authenticate", async (request, reply) => {
    try {
      await request.jwtVerify()
    } catch (err) {
      reply.send(err)
    }
  })
  .after(() => {
    fastify.route({
      method: 'GET',
      url: '/secret',
      preHandler: [fastify.authenticate],
      handler: (req, reply) => {
        reply.send('secret')
      }
    })
  })

fastify.post('/signup', (req, reply) => {
  const token = fastify.jwt.sign({
    foo: 'bar'
  })
  reply.send({
    token
  })
})

fastify.listen(3000, '0.0.0.0', function(err, address) {
  if (err) {
    fastify.log.error(err)
    process.exit(1)
  }
  fastify.log.info(`server listening on ${address}`)
})

We call the request.jwtVerify method, which is available after we call the fastify.register method.

If there’s an error, the catch block will be run.

To add some routes that require the auth token, we add the after callback with the routes defined by fastify.route .

preHandler runs before the route is called so that we can run the auth token check and call the route handler only if the token is valid.

Cookies

We can put the auth token in the cookies.

For example, we can write:

const fastify = require('fastify')()
const jwt = require('fastify-jwt')

fastify.register(jwt, {
  secret: 'key',
  cookie: {
    cookieName: 'token'
  }
})

fastify
  .register(require('fastify-cookie'))

fastify.get('/cookies', async (request, reply) => {
  const token = await reply.jwtSign({
    name: 'foo',
    role: ['admin', 'spy']
  })

reply
    .setCookie('token', token, {
      domain: '*',
      path: '/',
      secure: true,
      httpOnly: true,
      sameSite: true
    })
    .code(200)
    .send('Cookie sent')
})

fastify.get('/verifycookie', async (request, reply) => {
  try {
    await request.jwtVerify()
    reply.send({ code: 'OK', message: 'it works!' })
  }
  catch(error){
    reply.send(error);
  }
})

fastify.listen(3000, '0.0.0.0', function (err, address) {
  if (err) {
    fastify.log.error(err)
    process.exit(1)
  }
  fastify.log.info(`server listening on ${address}`)
})

We add the /cookies route to issue the cookie.

The setCookie is available after we register the fastify-cookie plugin.

We pass the token into the setCookie method to pass the cookie in the response header.

secure makes sure it’s sent over HTTPS.

httpOnly makes sure it’s only used with HTTP requests.

sameSite checks if the cookie is issued from the same site it’s used in.

In the verifycookie route, we call request.jwtVerify to verify the cookie before doing anything else.

Conclusion

We can use fastify-jwt to issue JSON web tokens and verify it.

Categories
Fastify

Add Basic Authentication to Our Fastify App with fastify-basic-auth

With the fastify-basic-auth library, we can add basic authentication to our Fastify app quickly.

In this article, we’ll look at how to use the library to add authentication to our Fastify app.

Installation

We can install the package by running:

npm i fastify-basic-auth

Adding Basic Auth

We can add basic auth to our Fastify app by writing some code.

For example, we can write:

const fastify = require('fastify')({
  logger: true
})

const authenticate = {realm: 'Westeros'}
fastify.register(require('fastify-basic-auth'), { validate, authenticate })

function validate (username, password, req, reply, done) {
  if (username === 'foo' && password === 'bar') {
    done()
  } else {
    done(new Error('invalid user'))
  }
}

fastify.after(() => {
  fastify.addHook('onRequest', fastify.basicAuth)

  fastify.get('/', (req, reply) => {
    reply.send({ hello: 'world' })
  })
})

fastify.listen(3000, '0.0.0.0',  function (err, address) {
  if (err) {
    fastify.log.error(err)
    process.exit(1)
  }
  fastify.log.info(`server listening on ${address}`)
})

We register the fastify-basic-auth plugin with validate and authenticate .

validate is a function to validate the username and password.

authenticate is an object to set the realm.

To add basic auth, we called addHook to add a hook that checks the username and password with validate on each request.

Any routes that are registered in the after hook have protection with basic auth.

The validate function can be async.

For example, we can write:

const fastify = require('fastify')({
  logger: true
})

const authenticate = {realm: 'Westeros'}
fastify.register(require('fastify-basic-auth'), { validate, authenticate })

async function validate (username, password, req, reply) {
  if (username !== 'foo' || password !== 'bar') {
    return new Error('invalid user')
  }
}

fastify.after(() => {
  fastify.addHook('onRequest', fastify.basicAuth)

  fastify.get('/', (req, reply) => {
    reply.send({ hello: 'world' })
  })
})

fastify.listen(3000, '0.0.0.0',  function (err, address) {
  if (err) {
    fastify.log.error(err)
    process.exit(1)
  }
  fastify.log.info(`server listening on ${address}`)
})

If validate is async, then we don’t need to call done .

Also, we can use it with the onRequest property:

const fastify = require('fastify')({
  logger: true
})

const authenticate = { realm: 'Westeros' }
fastify.register(require('fastify-basic-auth'), { validate, authenticate })
async function validate (username, password, req, reply) {
  if (username !== 'foo' || password !== 'bar') {
    return new Error('invalid user')
  }
}

fastify.after(() => {
  fastify.route({
    method: 'GET',
    url: '/',
    onRequest: fastify.basicAuth,
    handler: async (req, reply) => {
      return { hello: 'world' }
    }
  })
})

fastify.listen(3000, '0.0.0.0',  function (err, address) {
  if (err) {
    fastify.log.error(err)
    process.exit(1)
  }
  fastify.log.info(`server listening on ${address}`)
})

We set fastify.basicAuth as the value of onRequest to add basic auth to our GET / route.

Also, we can use it with fastify-auth :

const fastify = require('fastify')({
  logger: true
})

const authenticate = {realm: 'Westeros'}
fastify.register(require('fastify-auth'))
fastify.register(require('fastify-basic-auth'), { validate, authenticate })
async function validate (username, password, req, reply) {
  if (username !== 'foo' || password !== 'bar') {
    return new Error('invalid user')
  }
}

fastify.after(() => {
  fastify.addHook('preHandler', fastify.auth([fastify.basicAuth]))

fastify.route({
    method: 'GET',
    url: '/',
    onRequest: fastify.auth([fastify.basicAuth]),
    handler: async (req, reply) => {
      return { hello: 'world' }
    }
  })
})

fastify.listen(3000, '0.0.0.0',  function (err, address) {
  if (err) {
    fastify.log.error(err)
    process.exit(1)
  }
  fastify.log.info(`server listening on ${address}`)
})

We register the basic auth handler in the adfter hook and in the onRequest property of the GET / route.

Conclusion

The fastify-basic-auth library lets us add basic auth to our Fastify app with a few lines of code.

Categories
Fastify

Add Authentication to Our Fastify App with fastify-auth

With the fastify-auth library, we can add authentication to our Fastify app quickly.

In this article, we’ll look at how to use the library to add authentication to our Fastify app.

Install

We can install the library by running:

npm i fastify-auth

Add Authentication

We can add authentication to our app by writing:

const fastify = require('fastify')({
  logger: true
})

fastify
  .decorate('verifyJWTandLevel',  (request, reply, done) => {
    done()
  })
  .decorate('verifyUserAndPassword', (request, reply, done) => {
    console.log(request, reply)
    done()
  })
  .register(require('fastify-auth'))
  .after(() => {
    fastify.route({
      method: 'POST',
      url: '/auth-multiple',
      preHandler: fastify.auth([
        fastify.verifyJWTandLevel,
        fastify.verifyUserAndPassword
      ]),
      handler: (req, reply) => {
        req.log.info('Auth route')
        reply.send({ hello: 'world' })
      }
    })
  })

fastify.get('/', function (request, reply) {
  reply.send({ hello: 'world' })
})

fastify.listen(3000, '0.0.0.0',  function (err, address) {
  if (err) {
    fastify.log.error(err)
    process.exit(1)
  }
  fastify.log.info(`server listening on ${address}`)
})

We call decorate to add our authentication handlers to our app.

The callback has the request with the request data.

reply lets us set the response.

done is a function we call to call the next middleware.

If there’s an error, we pass in an Error instance to the done function.

We call the register method to register the fasify-auth plugin.

When we make a POST request to the auth-multiple route, we see the request and reply logged.

The routes that are registered in the after callback will have the auth handlers available.

They’re run since we set them to the preHandler property to add the array of auth handlers to run.

The default relationship is an OR relationship.

If we want both handlers to be valid before running the route handler, then we write:

const fastify = require('fastify')({
  logger: true
})

fastify
  .decorate('verifyJWTandLevel',  (request, reply, done) => {
    console.log(request, reply)
    done()
  })
  .decorate('verifyUserAndPassword', (request, reply, done) => {
    console.log(request, reply)
    done()
  })
  .register(require('fastify-auth'))
  .after(() => {
    fastify.route({
      method: 'POST',
      url: '/auth-multiple',
      preHandler: fastify.auth([
        fastify.verifyJWTandLevel,
        fastify.verifyUserAndPassword
      ], {
        relation: 'and'
      }),
      handler: (req, reply) => {
        req.log.info('Auth route')
        reply.send({ hello: 'world' })
      }
    })
  })

fastify.get('/', function (request, reply) {
  reply.send({ hello: 'world' })
})

fastify.listen(3000, '0.0.0.0',  function (err, address) {
  if (err) {
    fastify.log.error(err)
    process.exit(1)
  }
  fastify.log.info(`server listening on ${address}`)
})

Fastify-auth supports promises returned by the functions.

So we can use async and await in our auth handler callbacks:

const fastify = require('fastify')({
  logger: true
})

fastify
  .decorate('asyncVerifyJWTandLevel', async function (request, reply) {
    console.log('asyncVerifyJWTandLevel');
    await validation()
  })
  .decorate('asyncVerifyUserAndPassword', function (request, reply) {
    console.log('asyncVerifyUserAndPassword');
    return Promise.resolve()
  })
  .register(require('fastify-auth'))
  .after(() => {
    fastify.route({
      method: 'POST',
      url: '/auth-multiple',
      preHandler: fastify.auth([
        fastify.asyncVerifyJWTandLevel,
        fastify.asyncVerifyUserAndPassword
      ]),
      handler: (req, reply) => {
        req.log.info('Auth route')
        reply.send({ hello: 'world' })
      }
    })
  })

fastify.get('/', function (request, reply) {
  reply.send({ hello: 'world' })
})

fastify.listen(3000, '0.0.0.0',  function (err, address) {
  if (err) {
    fastify.log.error(err)
    process.exit(1)
  }
  fastify.log.info(`server listening on ${address}`)
})

We use async and await with the asyncVerifyJWTandLevel handler.

And we return a promise within the asyncVerifyUserAndPassword handler.

Conclusion

We can add our own auth logic easily to our Fastify app with the fastify-auth plugin.

Categories
Express

Document Our Express API with the Swagger UI Express Library

Documenting APIs is painful and tedious.

However, we can make our lives easier with the Swagger UI Express library if we’re using Express.

In this article, we’ll look at how to use the library to document our Express API.

Installation

We can install the package by running:

npm i swagger-ui-express

Documenting Our Endpoints

We can document our endpoints by writing some code.

First, we add our swagger.json file by writing:

{
  "swagger": "2.0",
  "info": {
    "title": "some-app",
    "version": "Unknown"
  },
  "consumes": [
    "application/json"
  ],
  "produces": [
    "application/json"
  ],
  "paths": {
    "/{id}": {
      "parameters": [
        {
          "name": "id",
          "required": true,
          "in": "path",
          "type": "string",
          "description": "some id"
        }
      ],
      "get": {
        "operationId": "routeWithId",
        "summary": "some route",
        "description": "some route",
        "produces": [
          "application/json"
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "examples": {
              "application/json": "{ foo: 1 }"
            }
          }
        }
      }
    },
    "/": {
      "parameters": [],
      "get": {
        "operationId": "anotherRoute",
        "summary": "another route",
        "description": "another route",
        "produces": [
          "application/json"
        ],
        "responses": {
          "202": {
            "description": "202 response",
            "examples": {
              "application/json": "{ foo: 'bar' }"
            }
          }
        }
      }
    }
  }
}

It has all the information about the endpoints in our app.

The data includes the parameters required and the responses.

parameters has the parameters and responses has possible responses from the endpoint.

Then in our app file, we write:

index.js

const express = require('express');
const bodyParser = require('body-parser');
const swaggerUi = require('swagger-ui-express');
const swaggerDocument = require('./swagger.json');
const swaggerOptions = {
  swaggerOptions: {
    validatorUrl: null
  }
};

const app = express();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument, swaggerOptions));

app.get('/', (req, res) => {
  res.json({ foo: 'bar' });
});

app.get('/:id', (req, res) => {
  res.json({ foo: req.params.id });
});

app.listen(3000, () => console.log('server started'));

We require our swagger.json file and add the api-docs endpoint to show the document.

validatorUrl has the URL for Swagger’s validator for validating our document.

We just add:

app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument, swaggerOptions));

to add the endpoint and pass in the options for displaying the document.

The swaggerUi.setup method takes the document and options as arguments.

When we go to the /api-docs endpoint, we should see the Swagger interface and try requests with our app.

We can enter the ID for the /{id} endpoint and see the response after clicking Execute.

Custom CSS Styles

We can add custom CSS with the customCss property:

const express = require('express');
const bodyParser = require('body-parser');
const swaggerUi = require('swagger-ui-express');
const swaggerDocument = require('./swagger.json');
const swaggerOptions = {
  swaggerOptions: {
    validatorUrl: null,
  },
  customCss: '.swagger-ui .topbar { display: none }'
};

const app = express();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument, swaggerOptions));

app.get('/', (req, res) => {
  res.json({ foo: 'bar' });
});

app.get('/:id', (req, res) => {
  res.json({ foo: req.params.id });
});

app.listen(3000, () => console.log('server started'));

We hid the top bar with:

customCss: '.swagger-ui .topbar { display: none }'

Load Swagger from URL

We can load the Swagger file from a URL with the url option:

const express = require('express');
const app = express();
const swaggerUi = require('swagger-ui-express');

const options = {
  swaggerOptions: {
    url: 'http://petstore.swagger.io/v2/swagger.json'
  }
}

app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(null, options));

We can load more than one file:

const express = require('express');
const app = express();
const swaggerUi = require('swagger-ui-express');

const options = {
  explorer: true,
  swaggerOptions: {
    urls: [
      {
        url: 'http://petstore.swagger.io/v2/swagger.json',
        name: 'Spec1'
      },
      {
        url: 'http://petstore.swagger.io/v2/swagger.json',
        name: 'Spec2'
      }
    ]
  }
}

app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(null, options));

Conclusion

We can document our Express API easily with the Swagger UI Express library.

Categories
React

Add a Date Picker with Airbnb’s React Dates Package

We can add a date picker easily with Airbnb’s React Dates packages.

In this article, we’ll look at how to use it to add a date picker.

Installation

We install the required packages by running:

npm install --save react-dates moment

Basic Datepicker

We add the date picker to our React component by writing:

import React from "react";
import "react-dates/initialize";
import { DateRangePicker } from "react-dates";
import "react-dates/lib/css/_datepicker.css";

export default function App() {
  const [startDate, setStartDate] = React.useState();
  const [endDate, setEndDate] = React.useState();
  const [focusedInput, setFocusedInput] = React.useState();
  return (
    <div className="App">
      <DateRangePicker
        startDate={startDate}
        startDateId="start-date"
        endDate={endDate}
        endDateId="end-date"
        onDatesChange={({ startDate, endDate }) => {
          setStartDate(startDate);
          setEndDate(endDate);
        }}
        focusedInput={focusedInput}
        onFocusChange={(focusedInput) => setFocusedInput(focusedInput)}
      />
    </div>
  );
}

We import the react-dates/initialize package to run the initialization code.

And we import the CSS.

We add the date picker with the DateRangePicker component.

The listed props are all required.

startDate has the start date.

startDateId is the ID of the start date field.

endDate has the end date.

endDateId is the ID of the end date field.

onDatesChanges lets us update the start and end date states.

focusedInput sets whether the input is focused.

onFocusChange has the function to set the focusedInput state to set which field is focused.

Overriding Styles

We can override the styles by setting styles for a few classes.

For example, we can write:

styles.css

.CalendarDay__selected_span {
  background: #82e0aa;
  color: white;
  border: 1px solid lightred;
}

.CalendarDay__selected {
  background: red;
  color: white;
}

.CalendarDay__selected:hover {
  background: orange;
  color: white;
}

.CalendarDay__hovered_span:hover,
.CalendarDay__hovered_span {
  background: brown;
}

CalendarDay__selected_span is the class for the calendar boxes in between the dates.

CalendarDay__selected is the class for the selected start date.

CalendarDay__selected:hover is the pseudoclass for the selected start date when we hover over it.

CalendarDay__hovered_span sets the color for the end date box.

SingleDatePicker

We can also add the SingleDatePicker if we only want to pick a single date.

For example, we can write:

import React from "react";
import "react-dates/initialize";
import { SingleDatePicker } from "react-dates";
import "react-dates/lib/css/_datepicker.css";

export default function App() {
  const [date, setDate] = React.useState();
  const [focused, setFocused] = React.useState();
  return (
    <div className="App">
      <SingleDatePicker
        date={date}
        onDateChange={(date) => setDate(date)}
        focused={focused}
        onFocusChange={({ focused }) => setFocused(focused)}
        id="date"
      />
    </div>
  );
}

We add the SingleDatePicker component to add the date picker.

date has the date.

onDateChange lets us set the date.

focused has the focus date.

onFocusChanged lets us change the focus state.

id has the ID of the date field.

Conclusion

We can add a simple date range and date picker with the react-dates library.