Securing your API using Auth0 and Lock

Introduction

You don't necessarily have to be using the same things that I use on my project to follow along.  Use this as a general guideline to provide you with ideas on how to approach it.

I am not going to list every single library, package, etc. that I'm using on my project.  I'll list the ones that are important.

The front-end client uses the following tech:

  • Auth0, specifically their Lock widget
  • React
  • whatwg-fetch package

The API uses the following:

  • NodeJS
  • ExpressJS
  • jsonwebtoken package
  • express-bearer-token package

What this will NOT cover:

  • Getting Auth0 implemented with React
  • How to build a React app
  • How to build an API

This is only to help others who have already implemented Auth0 and have an API that their client is talking to that needs to be secured, but would like ideas on how to go about it.

Setup a non interactive client in Auth0

1.) Go to Auth0 and click on "Clients" in the left navigation (A) then "Create Client" (B):

2017-05-09 16_31_52-Clients.png

 

2.) Then enter a name for your non interactive client, make sure to select "Non Interactive Clients", and click "Create":

2017-05-09 16_30_20-Clients.png

3.) Follow the instructions that Auth0 provides you in how to set up the rest of the non interactive client.

 

The non interactive client will be used for providing us the access token.  I've tried it where the main client tries to provide the access token, but it doesn't work...at least not for me.

Retrieving the access token while using Auth0's Lock widget

You must have already implemented Auth0's Lock widget into your React app.  I used the following documentation to implement the Lock widget:  https://auth0.com/docs/quickstart/spa/react/01-login.  This section will assume that you followed the documentation and have a class called AuthService.

In your AuthService class (AuthService.js), we're going to create a method like the following:

  1. retrieveAccessToken() {
  2. return fetch('https://{ DOMAIN }/oauth/token', {
  3. method: 'POST',
  4. headers: {
  5. 'Content-Type': 'application/json',
  6. },
  7. body: JSON.stringify({
  8. client_id:"{ CLIENT ID FROM YOUR NON-INTERACTIVE AUTH0 CLIENT }",
  9. client_secret:"{ CLIENT SECRET FROM YOUR NON-INTERACTIVE AUTH0 CLIENT }",
  10. audience:"{ AUDIENCE VALUE }",
  11. grant_type:"client_credentials"}),
  12. })
  13. .then(function(responses) {
  14. return responses.json();
  15. })
  16. .then(function(accessKit) {
  17. return accessKit['access_token'];
  18. });
  19. }

 

In the above code, I am using fetch() which comes from the package, whatwg-fetch, so make sure you have that downloaded.  This lets me call the oauth URL that can be found in Auth0 at Clients ---> Your non interactive client ---> Advanced Settings ---> Endpoints:

2017-05-23 13_19_51-Client Settings.png

 

We're going to retrieve the access token as we're logging in using the Lock widget.  This method would be called along the way during the login process.  I called it after I have set the id token.

Check out the below process diagram to have a better visualization of how the process works:

2017-05-23 13_27_15-Drawing2 - Visio Professional.png

 

Sending the access token to the API

After you have retrieved the access token, you want to send it as a Bearer token to your API as a part of the Authorization header.  Below is a code snippet of how I sent it in my code.  You'll want to do something similar.

  1. static createExpenseCard(userId) {
  2. return fetch('http://localhost:3001/api/expense-card', {
  3. method: 'POST',
  4. headers: {
  5. 'Content-Type': 'application/json',
  6. 'Authorization': 'Bearer ' + localStorage.getItem('access_token'),
  7. },
  8. body: JSON.stringify({
  9. userId: userId,
  10. }),
  11. })
  12. .then(this.checkStatus)
  13. .then(function(response) {
  14. return response.json();
  15. });
  16. }

 

Checking the access token over at the API

Over on the server side, you want to check to make sure that the access token is valid.  The way I did this was using the following packages: jsonwebtoken, express-bearer-token, fs.  Below is the code snippet that is used, albeit still incomplete:

  1. app.use(function(req, res, next) {
  2. var cert = fs.readFileSync('./server/config/projectexpensecards.pem');
  3. let validAuthorization = true;
  4.  
  5. jwt.verify(req.token, cert, function(err, decoded) {
  6. if (err !== undefined && err !== null) {
  7. switch(err.name) {
  8. case 'UnauthorizedError':
  9. res.status(403).json('Unable to use the API without valid credentials.');
  10. validAuthorization = false;
  11. break;
  12. case 'JsonWebTokenError':
  13. res.status(403).json('Unable to use the API without valid tokens.');
  14. validAuthorization = false;
  15. break;
  16. default:
  17. res.status(500).json('Error occurred trying to get to the API.');
  18. validAuthorization = false;
  19. }
  20. }
  21.  
  22. // Test for decoded values and throw errors.
  23. console.log(decoded);
  24.  
  25. // If everything is valid, proceed onwards.
  26. if (validAuthorization) {
  27. next();
  28. }
  29. });
  30.  
  31.  
  32. });

You'll find plenty of tutorials out there that show you how to check for a valid access token if you're not using the same packages as me.  Maybe you already wrote your code to check this!

 

After the access token is checked and is good, then we continue with our business like usual.  I didn't make it too difficult right now with scopes since every user has the same permissions, but maybe in the future if I do, the server side code will definitely be more than just a check on the validity of the access token.