Crafting Node APIs, Part 4: Security

Previously: Crafting Node APIs part 1, part 2, part 3

Objective

Scott Wojan, projekt202 Principal Architect

Reggie Samuel, projekt202 Managing Architect

In this post, we will dive into how to secure the API with both authentication and authorization.

Security Options for an API

There are a number of security options available for securing an API:

  1. HTTP Basic Authorization: The downside of this is that you are sending the username and password in simple base64 encoding with every request. This is ripe for tampering.
  2. OAuth and OAuth2: These are both great options and would be the second way we would implement it, after the way we chose, which is JWT.
  3. JWT Tokens: Like OAuth and Oauth2, JWT tokens are an industry standard (RFC 7519) way to represent claims between two parties. JWT is a secure and easy way to secure an API.

Enabling the Security Features in the API

One of the configuration settings is the Boolean property server.enableSecurity. Set this value to "true." This will allow the middleware code for security in app.js to be added into the Restify pipeline.


Previously: Crafting Node APIs part 1, part 2 and part 3


 

How to Obtain a Token

Once security is enabled, nearly all requests -- except /users and /authenticate -- will need to have a JWT token set in the header. You obtain a JWT token by calling the /authenticate endpoint with the email and password you created for the user.

[code lang="shell"][/code]

You should again receive a 200 OK response with the following application/json data containing the user's info:

[code lang="js"]{ "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vMTI3LjAuMC4xOjMwMDAiLCJzdWIiOiJ1c2Vycy8xIiwic2NvcGUiOiIiLCJqdGkiOiJkNDJkMmUxZi0yZWRkLTRlMDMtYmQ5My00YzhmODNmYjM0MzYiLCJpYXQiOjE0NzUxNzc5NjAsImV4cCI6MTQ3NTE4NTE2MDYwM30.5k6YGXwPhXfSl2FIs1cRNuYni7SrlWoNBFIvN67nE1w" }[/code]

How Do You Use the Token?

Attach this token as the Authorization header with the value set to Bearer [your_token]. We are using this method because the HTTP spec specifically outlines that this is the http authentication scheme to use for these types of tokens. (OAuth2 uses this method as well.) This goes back to the goal of not inventing stuff; the http spec probably already has an answer for it.

A properly-formatted request for a list of a user's todos would look like the following:

[code lang="shell"]curl -X GET -H "Accept: application/json" -H "Content-Type: application/json" -H "Cache-Control: no-cache" -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vMTI3LjAuMC4xOjMwMDAiLCJzdWIiOiJ1c2Vycy8xIiwic2NvcGUiOiIiLCJqdGkiOiJkNDJkMmUxZi0yZWRkLTRlMDMtYmQ5My00YzhmODNmYjM0MzYiLCJpYXQiOjE0NzUxNzc5NjAsImV4cCI6MTQ3NTE4NTE2MDYwM30.5k6YGXwPhXfSl2FIs1cRNuYni7SrlWoNBFIvN67nE1w" "http://127.0.0.1:3000/users/1/todos" [/code]

So How Does This Work?

How a JWT Token is Issued

Sequence Diagram for JWT Token Creation

  1. Restify calls the authenticate controller.
  2. The authenticate controller gets the user info from the ORM.
  3. The authenticate controller verifies the stored hashed password matches the one sent.
  4. If the passwords do not match, the user gets a 401 Unauthorized response.
  5. If the passwords do match, the authenticate controller calls the claim service to generate a new claim.
  6. The claim service returns the claim to the authenticate controller, which then responds with a 200 OK and the token in a json response body.

How a Request is Authorized

Sequence Diagram for How a Request is Authorized

  1. Restify hands the request to the authentication middleware.
  2. The authentication middleware looks for an Authorization header value. If that value isn't set, it will return a 401 Unauthorized response with a header value "WWW-Authenticate" set to "Bearer api-key." (This complies with RFC7235, Section 3.1.)
  3. The authentication middleware passes the token to the claim service for validation.
  4. The claim service then looks up the stored key based on the token and validates it using the key that was used to sign it.
  5. If the JWT token that was sent is valid, the next middleware component in the Restify pipeline will be called. If it's invalid, the client will receive a 401 Unauthorized response.

Conclusion

In this post, we demonstrated how you can apply authentication and authorization to an API. In Part 5, we will outline some remaining considerations you should address when crafting an API.