├── README.md ├── backend ├── .env.example ├── .gitignore ├── package-lock.json ├── package.json └── src │ ├── authz │ └── check-jwt.js │ ├── config │ └── env.dev.js │ ├── index.js │ └── messages │ ├── messages.router.js │ └── messages.service.js ├── frontend ├── .env.example ├── .gitignore ├── package-lock.json ├── package.json ├── public │ └── index.html └── src │ ├── app.css │ ├── app.js │ ├── auth │ ├── auth0-provider-with-history.js │ └── protected-route.js │ ├── components │ ├── auth-nav.js │ ├── authentication-button.js │ ├── footer.js │ ├── hero.js │ ├── home-content.js │ ├── index.js │ ├── loading.js │ ├── login-button.js │ ├── logout-button.js │ ├── main-nav.js │ ├── nav-bar.js │ └── signup-button.js │ ├── index.css │ ├── index.js │ └── views │ ├── external-api.js │ ├── home.js │ ├── index.js │ └── profile.js └── images └── auth0-react.jpg /README.md: -------------------------------------------------------------------------------- 1 | # Auth0 ♥️ React Workshop 2 | 3 | This repository is set up to facilitate a hands-on workshop with authentication in React using Auth0. There are a few additional sections for adding multi-factor authentication and deployment. 4 | 5 | ![Auth0 Loves React](./images/auth0-react.jpg) 6 | 7 | _For the majority of the hands-on portion, you will follow this blog post, [The Complete Guide to React User Authentication](https://auth0.com/blog/complete-guide-to-react-user-authentication/), created by [Dan Arias](https://auth0.com/blog/authors/dan-arias/). Thanks Dan!_ 8 | 9 | ## About this Repository 10 | 11 | In this workshop, you'll learn about several crucial concepts. 12 | 13 | - modern authentication workflows 14 | - handling authentication in React using React Hooks, Context API, etc. 15 | - JSON Web Tokens 16 | - securely calling APIs 17 | - (bonus) multi-factor authentication 18 | - (bonus) how to deploy/host your application 19 | 20 | During the majority of the hands-on portion, you'll follow **[this article](https://auth0.com/blog/complete-guide-to-react-user-authentication/)** for the detailed walkthrough. In that article, the frontend and backend projects are in two different repositories. **However, this repository already includes both projects, a React frontend and a Node/Express backend**. 21 | 22 | Two important notes on this... 23 | 24 | > 1. When the blog post mentions the `auth0-react-sample` directory in the _Get the Starter Application_ section, you will instead use the `frontend` directory from this repository. 25 | 26 | > 2. When the blog post mentions the `auth0-express-js-sample` directory in the _Calling an API_ section, you will instead use the `backend` directory from this repository. 27 | 28 | ### Branches 29 | 30 | Each step has a corresponding branch with the starting code for that step. If you get behind, you can always skip ahead by checking out the next branch. 31 | 32 | For example, if you are on Step 1, you would check out the `step-1` branch. To get the finished code from Step 1, you would check out the `step-2` branch. 33 | 34 | ### Expectations and Requirements 35 | 36 | To participate in this workshop, it is expected that you have at least beginner knowledge of JavaScript, React.js, and Git. 37 | 38 | You will also need to have a few things installed. 39 | 40 | - [node.js](https://nodejs.org/en/download/) 41 | - code editor ([VS Code](https://code.visualstudio.com/) is recommended) 42 | - [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git/) 43 | - [AWS Amplify CLI](https://docs.amplify.aws/cli) (for deploying to Amplify) 44 | 45 | ## Sign up for Auth0 46 | 47 | If you haven't already, [sign up for a free Auth0 account](https://a0.to/react-workshop-signup), which offers you: 48 | 49 | - 7,000 [free active users and unlimited logins](https://auth0.com/pricing/). 50 | - A [centralized, ready-to-ship login page](https://auth0.com/universal-login) for Web, iOS & Android. 51 | - Up to 2 [social identity providers](https://auth0.com/docs/connections/identity-providers-social) like Google and Facebook login. 52 | - Unlimited [serverless Rules](https://auth0.com/docs/rules/current) to customize and extend Auth0's capabilities. 53 | 54 | During the sign-up process, you will create an [Auth0 Tenant](https://auth0.com/docs/getting-started/the-basics#account-and-tenants), which is a container that Auth0 uses to store your identity service configuration and your users in isolation. No other Auth0 customer can peek into or access your tenant. 55 | 56 | ## Workshop Overview 57 | 58 | **Step 0:** Overview of Authentication 59 | 60 | You can find the slides [here](https://a0.to/react-workshop-slides). 61 | 62 | **Step 1:** Get the Starter Application 63 | 64 | Start by cloning this repository. 65 | 66 | ```bash 67 | git clone https://github.com/jamesqquick/auth0-react-workshop.git 68 | ``` 69 | 70 | Check out the `step-1` branch. 71 | 72 | ```bash 73 | git checkout step-1 74 | ``` 75 | 76 | [Follow the hands-on instructions](https://auth0.com/blog/complete-guide-to-react-user-authentication/#Get-the-Starter-Application) 77 | 78 | **Step 2:** Connect React with Auth0 79 | 80 | Check out the `step-2` branch. 81 | 82 | ```bash 83 | git checkout step-2 84 | ``` 85 | 86 | [Follow the hands-on instructions](https://auth0.com/blog/complete-guide-to-react-user-authentication/#Connect-React-with-Auth0) 87 | 88 | **Step 3:** Setup the Auth0 React SDK 89 | 90 | Check out the `step-3` branch. 91 | 92 | ```bash 93 | git checkout step-3 94 | ``` 95 | 96 | [Follow the hands-on instructions](https://auth0.com/blog/complete-guide-to-react-user-authentication/#Set-Up-the-Auth0-React-SDK) 97 | 98 | **Step 4:** Add User Authentication 99 | 100 | Check out the `step-4` branch. 101 | 102 | ```bash 103 | git checkout step-4 104 | ``` 105 | 106 | [Follow the hands-on instructions](https://auth0.com/blog/complete-guide-to-react-user-authentication/#Add-User-Authentication) 107 | 108 | **Step 5:** Retrieving User Information 109 | 110 | Check out the `step-5` branch. 111 | 112 | ```bash 113 | git checkout step-5 114 | ``` 115 | 116 | [Follow the hands-on instructions](https://auth0.com/blog/complete-guide-to-react-user-authentication/#Retrieving-User-Information) 117 | 118 | **Step 6:** Protecting Routes 119 | 120 | Check out the `step-6` branch. 121 | 122 | ```bash 123 | git checkout step-6 124 | ``` 125 | 126 | [Follow the hands-on instructions](https://auth0.com/blog/complete-guide-to-react-user-authentication/#Protecting-Routes) 127 | 128 | **Step 7:** Calling an API 129 | 130 | Check out the `step-7` branch. 131 | 132 | ```bash 133 | git checkout step-7 134 | ``` 135 | 136 | [Follow the hands-on instructions](https://auth0.com/blog/complete-guide-to-react-user-authentication/#Calling-an-API) 137 | 138 | ## Hosting (Bonus) 139 | 140 | ### Hosting with AWS Amplify 141 | 142 | For deploying the React application to AWS Amplify, you'll need the [Amplify CLI](https://docs.amplify.aws/cli/start/install) installed and a user profile set up in AWS that has sufficient access. If you don't have a user created, you can create one in the steps below. 143 | 144 | > Make sure to navigate into the `frontend` directory in your terminal if you aren't already. 145 | 146 | Configure the Amplify CLI. 147 | 148 | `amplify configure` 149 | 150 | You will then be taken to the browser where you will need to login with your AWS credentials. After you have logged in successfully, continue in the terminal to setup the region and username. 151 | 152 | `Region` - choose an appropriate region for your site to be hosted in 153 | 154 | `Username` - choose a username for the new user you will create 155 | 156 | You should then be taken back to the browser where you can finish creating the new user. Make sure to choose the following configuration for your user. 157 | 158 | `AWS Access Type` - programmatic access 159 | 160 | `Permissions` - you can choose `AdministratorAccess` for demo purposes ( keep in mind, it is recommended to restrict this access more appropriately with a real application) 161 | 162 | `Tags` - none 163 | 164 | After you've gone through those settings, click `Create User` and take note of the `Access key ID` and `Secret access key`. Follow the details in the command line by pasting in these two properties appropriately. Lastly, choose a profile name (**remember this as you'll need it shortly**). 165 | 166 | With the CLI configured, now initialize the React project as an AWS Amplify project. 167 | 168 | `amplify init` 169 | 170 | Choose a name for your project, and the CLI should complete the following configurations. If not, enter them manually. 171 | 172 | - Default editor - Visual Studio Code 173 | - App type - JavaScript 174 | - JavaScript framework - `react` 175 | - source directory - `src` 176 | - dist directory - `build` 177 | - build command - `npm run-script build` 178 | - start command - `npm run-script start` 179 | 180 | If you're prompted to create a new environment, give it a name. Then, **selected the `AWS profile` you just created**. 181 | 182 | Now, run the following command to add hosting to the project. Make sure to choose `Hosting with Amplify Console` and then `Manual`. 183 | 184 | `amplify hosting add` 185 | 186 | And finally, publish the project. 187 | 188 | `amplify publish` 189 | 190 | After your application has been deployed to Amplify, you should see an HTTPS URL in the terminal for your deployed app. Open it in the browser to see the app itself. 191 | 192 | For authentication to work in this deployed app, you'll need to update the following settings in the Auth0 dashboard with the deployed URL. You can add multiple values in these properties by comma-separting them. 193 | 194 | - allowed callback urls 195 | - allowed logout urls 196 | - allowed web origins 197 | 198 | Now, you should be able to login/logout in your deployed application. 199 | 200 | ## Add Multi-Factor Authentication (Bonus) 201 | 202 | To add multi-factor authentication to the app, in the Auth0 dashboard navigate to `Security` -> `Multi-factor Auth`. Then, click on the `Phone Message` section and choose the following options. There are several different options, but a phone message works well here. For more info, refer to the [Multi-Factor Authentication docs](https://auth0.com/docs/mfa). 203 | 204 | - Choose a delivery provider - Auth0 205 | - Choose a delivery method - SMS 206 | 207 | Make sure that the toggle in the top right is set to the green/on state. Then, go back to the `Multi-factor Authentication` page. Under `Define policies`, set `Require Mutli-factor Auth` to `Always`. 208 | 209 | The next time you log into your app, you should be prompted to enter a code that was sent to you via text. 210 | -------------------------------------------------------------------------------- /backend/.env.example: -------------------------------------------------------------------------------- 1 | SERVER_PORT=6060 2 | CLIENT_ORIGIN_URL=http://localhost:4040 3 | AUTH0_AUDIENCE= 4 | AUTH0_DOMAIN= -------------------------------------------------------------------------------- /backend/.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist 3 | /node_modules 4 | 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | 13 | # OS 14 | .DS_Store 15 | 16 | # Tests 17 | /coverage 18 | /.nyc_output 19 | 20 | # IDEs and editors 21 | /.idea 22 | .project 23 | .classpath 24 | .c9/ 25 | *.launch 26 | .settings/ 27 | *.sublime-workspace 28 | 29 | # IDE - VSCode 30 | .vscode/* 31 | !.vscode/settings.json 32 | !.vscode/tasks.json 33 | !.vscode/launch.json 34 | !.vscode/extensions.json 35 | 36 | .env -------------------------------------------------------------------------------- /backend/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-express-js", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@sindresorhus/is": { 8 | "version": "0.14.0", 9 | "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", 10 | "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", 11 | "dev": true 12 | }, 13 | "@szmarczak/http-timer": { 14 | "version": "1.1.2", 15 | "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", 16 | "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", 17 | "dev": true, 18 | "requires": { 19 | "defer-to-connect": "^1.0.1" 20 | } 21 | }, 22 | "@types/body-parser": { 23 | "version": "1.19.0", 24 | "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", 25 | "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==", 26 | "requires": { 27 | "@types/connect": "*", 28 | "@types/node": "*" 29 | } 30 | }, 31 | "@types/color-name": { 32 | "version": "1.1.1", 33 | "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", 34 | "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", 35 | "dev": true 36 | }, 37 | "@types/connect": { 38 | "version": "3.4.33", 39 | "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz", 40 | "integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==", 41 | "requires": { 42 | "@types/node": "*" 43 | } 44 | }, 45 | "@types/express": { 46 | "version": "4.17.7", 47 | "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.7.tgz", 48 | "integrity": "sha512-dCOT5lcmV/uC2J9k0rPafATeeyz+99xTt54ReX11/LObZgfzJqZNcW27zGhYyX+9iSEGXGt5qLPwRSvBZcLvtQ==", 49 | "requires": { 50 | "@types/body-parser": "*", 51 | "@types/express-serve-static-core": "*", 52 | "@types/qs": "*", 53 | "@types/serve-static": "*" 54 | } 55 | }, 56 | "@types/express-jwt": { 57 | "version": "0.0.42", 58 | "resolved": "https://registry.npmjs.org/@types/express-jwt/-/express-jwt-0.0.42.tgz", 59 | "integrity": "sha512-WszgUddvM1t5dPpJ3LhWNH8kfNN8GPIBrAGxgIYXVCEGx6Bx4A036aAuf/r5WH9DIEdlmp7gHOYvSM6U87B0ag==", 60 | "requires": { 61 | "@types/express": "*", 62 | "@types/express-unless": "*" 63 | } 64 | }, 65 | "@types/express-serve-static-core": { 66 | "version": "4.17.9", 67 | "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.9.tgz", 68 | "integrity": "sha512-DG0BYg6yO+ePW+XoDENYz8zhNGC3jDDEpComMYn7WJc4mY1Us8Rw9ax2YhJXxpyk2SF47PQAoQ0YyVT1a0bEkA==", 69 | "requires": { 70 | "@types/node": "*", 71 | "@types/qs": "*", 72 | "@types/range-parser": "*" 73 | } 74 | }, 75 | "@types/express-unless": { 76 | "version": "0.5.1", 77 | "resolved": "https://registry.npmjs.org/@types/express-unless/-/express-unless-0.5.1.tgz", 78 | "integrity": "sha512-5fuvg7C69lemNgl0+v+CUxDYWVPSfXHhJPst4yTLcqi4zKJpORCxnDrnnilk3k0DTq/WrAUdvXFs01+vUqUZHw==", 79 | "requires": { 80 | "@types/express": "*" 81 | } 82 | }, 83 | "@types/mime": { 84 | "version": "2.0.3", 85 | "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz", 86 | "integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==" 87 | }, 88 | "@types/node": { 89 | "version": "14.6.2", 90 | "resolved": "https://registry.npmjs.org/@types/node/-/node-14.6.2.tgz", 91 | "integrity": "sha512-onlIwbaeqvZyniGPfdw/TEhKIh79pz66L1q06WUQqJLnAb6wbjvOtepLYTGHTqzdXgBYIE3ZdmqHDGsRsbBz7A==" 92 | }, 93 | "@types/qs": { 94 | "version": "6.9.4", 95 | "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.4.tgz", 96 | "integrity": "sha512-+wYo+L6ZF6BMoEjtf8zB2esQsqdV6WsjRK/GP9WOgLPrq87PbNWgIxS76dS5uvl/QXtHGakZmwTznIfcPXcKlQ==" 97 | }, 98 | "@types/range-parser": { 99 | "version": "1.2.3", 100 | "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", 101 | "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==" 102 | }, 103 | "@types/serve-static": { 104 | "version": "1.13.5", 105 | "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.5.tgz", 106 | "integrity": "sha512-6M64P58N+OXjU432WoLLBQxbA0LRGBCRm7aAGQJ+SMC1IMl0dgRVi9EFfoDcS2a7Xogygk/eGN94CfwU9UF7UQ==", 107 | "requires": { 108 | "@types/express-serve-static-core": "*", 109 | "@types/mime": "*" 110 | } 111 | }, 112 | "abbrev": { 113 | "version": "1.1.1", 114 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", 115 | "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", 116 | "dev": true 117 | }, 118 | "accepts": { 119 | "version": "1.3.7", 120 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", 121 | "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", 122 | "requires": { 123 | "mime-types": "~2.1.24", 124 | "negotiator": "0.6.2" 125 | } 126 | }, 127 | "ansi-align": { 128 | "version": "3.0.0", 129 | "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", 130 | "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==", 131 | "dev": true, 132 | "requires": { 133 | "string-width": "^3.0.0" 134 | }, 135 | "dependencies": { 136 | "string-width": { 137 | "version": "3.1.0", 138 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", 139 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", 140 | "dev": true, 141 | "requires": { 142 | "emoji-regex": "^7.0.1", 143 | "is-fullwidth-code-point": "^2.0.0", 144 | "strip-ansi": "^5.1.0" 145 | } 146 | } 147 | } 148 | }, 149 | "ansi-regex": { 150 | "version": "4.1.0", 151 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", 152 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", 153 | "dev": true 154 | }, 155 | "ansi-styles": { 156 | "version": "4.2.1", 157 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", 158 | "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", 159 | "dev": true, 160 | "requires": { 161 | "@types/color-name": "^1.1.1", 162 | "color-convert": "^2.0.1" 163 | } 164 | }, 165 | "anymatch": { 166 | "version": "3.1.1", 167 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", 168 | "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", 169 | "dev": true, 170 | "requires": { 171 | "normalize-path": "^3.0.0", 172 | "picomatch": "^2.0.4" 173 | } 174 | }, 175 | "array-flatten": { 176 | "version": "1.1.1", 177 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 178 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 179 | }, 180 | "async": { 181 | "version": "1.5.2", 182 | "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", 183 | "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" 184 | }, 185 | "axios": { 186 | "version": "0.19.2", 187 | "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", 188 | "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", 189 | "requires": { 190 | "follow-redirects": "1.5.10" 191 | } 192 | }, 193 | "balanced-match": { 194 | "version": "1.0.0", 195 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 196 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 197 | "dev": true 198 | }, 199 | "binary-extensions": { 200 | "version": "2.1.0", 201 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", 202 | "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", 203 | "dev": true 204 | }, 205 | "body-parser": { 206 | "version": "1.19.0", 207 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", 208 | "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", 209 | "requires": { 210 | "bytes": "3.1.0", 211 | "content-type": "~1.0.4", 212 | "debug": "2.6.9", 213 | "depd": "~1.1.2", 214 | "http-errors": "1.7.2", 215 | "iconv-lite": "0.4.24", 216 | "on-finished": "~2.3.0", 217 | "qs": "6.7.0", 218 | "raw-body": "2.4.0", 219 | "type-is": "~1.6.17" 220 | } 221 | }, 222 | "boxen": { 223 | "version": "4.2.0", 224 | "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", 225 | "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", 226 | "dev": true, 227 | "requires": { 228 | "ansi-align": "^3.0.0", 229 | "camelcase": "^5.3.1", 230 | "chalk": "^3.0.0", 231 | "cli-boxes": "^2.2.0", 232 | "string-width": "^4.1.0", 233 | "term-size": "^2.1.0", 234 | "type-fest": "^0.8.1", 235 | "widest-line": "^3.1.0" 236 | } 237 | }, 238 | "brace-expansion": { 239 | "version": "1.1.11", 240 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 241 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 242 | "dev": true, 243 | "requires": { 244 | "balanced-match": "^1.0.0", 245 | "concat-map": "0.0.1" 246 | } 247 | }, 248 | "braces": { 249 | "version": "3.0.2", 250 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 251 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 252 | "dev": true, 253 | "requires": { 254 | "fill-range": "^7.0.1" 255 | } 256 | }, 257 | "buffer-equal-constant-time": { 258 | "version": "1.0.1", 259 | "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", 260 | "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" 261 | }, 262 | "bytes": { 263 | "version": "3.1.0", 264 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", 265 | "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" 266 | }, 267 | "cacheable-request": { 268 | "version": "6.1.0", 269 | "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", 270 | "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", 271 | "dev": true, 272 | "requires": { 273 | "clone-response": "^1.0.2", 274 | "get-stream": "^5.1.0", 275 | "http-cache-semantics": "^4.0.0", 276 | "keyv": "^3.0.0", 277 | "lowercase-keys": "^2.0.0", 278 | "normalize-url": "^4.1.0", 279 | "responselike": "^1.0.2" 280 | }, 281 | "dependencies": { 282 | "get-stream": { 283 | "version": "5.2.0", 284 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", 285 | "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", 286 | "dev": true, 287 | "requires": { 288 | "pump": "^3.0.0" 289 | } 290 | }, 291 | "lowercase-keys": { 292 | "version": "2.0.0", 293 | "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", 294 | "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", 295 | "dev": true 296 | } 297 | } 298 | }, 299 | "camelcase": { 300 | "version": "5.3.1", 301 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", 302 | "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", 303 | "dev": true 304 | }, 305 | "chalk": { 306 | "version": "3.0.0", 307 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", 308 | "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", 309 | "dev": true, 310 | "requires": { 311 | "ansi-styles": "^4.1.0", 312 | "supports-color": "^7.1.0" 313 | }, 314 | "dependencies": { 315 | "has-flag": { 316 | "version": "4.0.0", 317 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 318 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 319 | "dev": true 320 | }, 321 | "supports-color": { 322 | "version": "7.2.0", 323 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 324 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 325 | "dev": true, 326 | "requires": { 327 | "has-flag": "^4.0.0" 328 | } 329 | } 330 | } 331 | }, 332 | "chokidar": { 333 | "version": "3.4.2", 334 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.2.tgz", 335 | "integrity": "sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A==", 336 | "dev": true, 337 | "requires": { 338 | "anymatch": "~3.1.1", 339 | "braces": "~3.0.2", 340 | "fsevents": "~2.1.2", 341 | "glob-parent": "~5.1.0", 342 | "is-binary-path": "~2.1.0", 343 | "is-glob": "~4.0.1", 344 | "normalize-path": "~3.0.0", 345 | "readdirp": "~3.4.0" 346 | } 347 | }, 348 | "ci-info": { 349 | "version": "2.0.0", 350 | "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", 351 | "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", 352 | "dev": true 353 | }, 354 | "cli-boxes": { 355 | "version": "2.2.0", 356 | "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.0.tgz", 357 | "integrity": "sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w==", 358 | "dev": true 359 | }, 360 | "clone-response": { 361 | "version": "1.0.2", 362 | "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", 363 | "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", 364 | "dev": true, 365 | "requires": { 366 | "mimic-response": "^1.0.0" 367 | } 368 | }, 369 | "color-convert": { 370 | "version": "2.0.1", 371 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 372 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 373 | "dev": true, 374 | "requires": { 375 | "color-name": "~1.1.4" 376 | } 377 | }, 378 | "color-name": { 379 | "version": "1.1.4", 380 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 381 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 382 | "dev": true 383 | }, 384 | "concat-map": { 385 | "version": "0.0.1", 386 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 387 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 388 | "dev": true 389 | }, 390 | "configstore": { 391 | "version": "5.0.1", 392 | "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", 393 | "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", 394 | "dev": true, 395 | "requires": { 396 | "dot-prop": "^5.2.0", 397 | "graceful-fs": "^4.1.2", 398 | "make-dir": "^3.0.0", 399 | "unique-string": "^2.0.0", 400 | "write-file-atomic": "^3.0.0", 401 | "xdg-basedir": "^4.0.0" 402 | } 403 | }, 404 | "content-disposition": { 405 | "version": "0.5.3", 406 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", 407 | "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", 408 | "requires": { 409 | "safe-buffer": "5.1.2" 410 | } 411 | }, 412 | "content-type": { 413 | "version": "1.0.4", 414 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 415 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 416 | }, 417 | "cookie": { 418 | "version": "0.4.0", 419 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", 420 | "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" 421 | }, 422 | "cookie-signature": { 423 | "version": "1.0.6", 424 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 425 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 426 | }, 427 | "cors": { 428 | "version": "2.8.5", 429 | "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", 430 | "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", 431 | "requires": { 432 | "object-assign": "^4", 433 | "vary": "^1" 434 | } 435 | }, 436 | "crypto-random-string": { 437 | "version": "2.0.0", 438 | "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", 439 | "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", 440 | "dev": true 441 | }, 442 | "debug": { 443 | "version": "2.6.9", 444 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 445 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 446 | "requires": { 447 | "ms": "2.0.0" 448 | } 449 | }, 450 | "decompress-response": { 451 | "version": "3.3.0", 452 | "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", 453 | "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", 454 | "dev": true, 455 | "requires": { 456 | "mimic-response": "^1.0.0" 457 | } 458 | }, 459 | "deep-extend": { 460 | "version": "0.6.0", 461 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", 462 | "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", 463 | "dev": true 464 | }, 465 | "defer-to-connect": { 466 | "version": "1.1.3", 467 | "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", 468 | "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", 469 | "dev": true 470 | }, 471 | "depd": { 472 | "version": "1.1.2", 473 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 474 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 475 | }, 476 | "destroy": { 477 | "version": "1.0.4", 478 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 479 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 480 | }, 481 | "dot-prop": { 482 | "version": "5.2.0", 483 | "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.2.0.tgz", 484 | "integrity": "sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A==", 485 | "dev": true, 486 | "requires": { 487 | "is-obj": "^2.0.0" 488 | } 489 | }, 490 | "dotenv": { 491 | "version": "8.2.0", 492 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", 493 | "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" 494 | }, 495 | "duplexer3": { 496 | "version": "0.1.4", 497 | "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", 498 | "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", 499 | "dev": true 500 | }, 501 | "ecdsa-sig-formatter": { 502 | "version": "1.0.11", 503 | "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", 504 | "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", 505 | "requires": { 506 | "safe-buffer": "^5.0.1" 507 | } 508 | }, 509 | "ee-first": { 510 | "version": "1.1.1", 511 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 512 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 513 | }, 514 | "emoji-regex": { 515 | "version": "7.0.3", 516 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", 517 | "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", 518 | "dev": true 519 | }, 520 | "encodeurl": { 521 | "version": "1.0.2", 522 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 523 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 524 | }, 525 | "end-of-stream": { 526 | "version": "1.4.4", 527 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", 528 | "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", 529 | "dev": true, 530 | "requires": { 531 | "once": "^1.4.0" 532 | } 533 | }, 534 | "escape-goat": { 535 | "version": "2.1.1", 536 | "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", 537 | "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", 538 | "dev": true 539 | }, 540 | "escape-html": { 541 | "version": "1.0.3", 542 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 543 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 544 | }, 545 | "etag": { 546 | "version": "1.8.1", 547 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 548 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 549 | }, 550 | "express": { 551 | "version": "4.17.1", 552 | "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", 553 | "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", 554 | "requires": { 555 | "accepts": "~1.3.7", 556 | "array-flatten": "1.1.1", 557 | "body-parser": "1.19.0", 558 | "content-disposition": "0.5.3", 559 | "content-type": "~1.0.4", 560 | "cookie": "0.4.0", 561 | "cookie-signature": "1.0.6", 562 | "debug": "2.6.9", 563 | "depd": "~1.1.2", 564 | "encodeurl": "~1.0.2", 565 | "escape-html": "~1.0.3", 566 | "etag": "~1.8.1", 567 | "finalhandler": "~1.1.2", 568 | "fresh": "0.5.2", 569 | "merge-descriptors": "1.0.1", 570 | "methods": "~1.1.2", 571 | "on-finished": "~2.3.0", 572 | "parseurl": "~1.3.3", 573 | "path-to-regexp": "0.1.7", 574 | "proxy-addr": "~2.0.5", 575 | "qs": "6.7.0", 576 | "range-parser": "~1.2.1", 577 | "safe-buffer": "5.1.2", 578 | "send": "0.17.1", 579 | "serve-static": "1.14.1", 580 | "setprototypeof": "1.1.1", 581 | "statuses": "~1.5.0", 582 | "type-is": "~1.6.18", 583 | "utils-merge": "1.0.1", 584 | "vary": "~1.1.2" 585 | } 586 | }, 587 | "express-jwt": { 588 | "version": "6.0.0", 589 | "resolved": "https://registry.npmjs.org/express-jwt/-/express-jwt-6.0.0.tgz", 590 | "integrity": "sha512-C26y9myRjx7CyhZ+BAT3p+gQyRCoDZ7qo8plCvLDaRT6je6ALIAQknT6XLVQGFKwIy/Ux7lvM2MNap5dt0T7gA==", 591 | "requires": { 592 | "async": "^1.5.0", 593 | "express-unless": "^0.3.0", 594 | "jsonwebtoken": "^8.1.0", 595 | "lodash.set": "^4.0.0" 596 | } 597 | }, 598 | "express-unless": { 599 | "version": "0.3.1", 600 | "resolved": "https://registry.npmjs.org/express-unless/-/express-unless-0.3.1.tgz", 601 | "integrity": "sha1-JVfBRudb65A+LSR/m1ugFFJpbiA=" 602 | }, 603 | "fill-range": { 604 | "version": "7.0.1", 605 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 606 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 607 | "dev": true, 608 | "requires": { 609 | "to-regex-range": "^5.0.1" 610 | } 611 | }, 612 | "finalhandler": { 613 | "version": "1.1.2", 614 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", 615 | "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", 616 | "requires": { 617 | "debug": "2.6.9", 618 | "encodeurl": "~1.0.2", 619 | "escape-html": "~1.0.3", 620 | "on-finished": "~2.3.0", 621 | "parseurl": "~1.3.3", 622 | "statuses": "~1.5.0", 623 | "unpipe": "~1.0.0" 624 | } 625 | }, 626 | "follow-redirects": { 627 | "version": "1.5.10", 628 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", 629 | "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", 630 | "requires": { 631 | "debug": "=3.1.0" 632 | }, 633 | "dependencies": { 634 | "debug": { 635 | "version": "3.1.0", 636 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 637 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 638 | "requires": { 639 | "ms": "2.0.0" 640 | } 641 | } 642 | } 643 | }, 644 | "forwarded": { 645 | "version": "0.1.2", 646 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", 647 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 648 | }, 649 | "fresh": { 650 | "version": "0.5.2", 651 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 652 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 653 | }, 654 | "fsevents": { 655 | "version": "2.1.3", 656 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", 657 | "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", 658 | "dev": true, 659 | "optional": true 660 | }, 661 | "get-stream": { 662 | "version": "4.1.0", 663 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", 664 | "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", 665 | "dev": true, 666 | "requires": { 667 | "pump": "^3.0.0" 668 | } 669 | }, 670 | "glob-parent": { 671 | "version": "5.1.1", 672 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", 673 | "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", 674 | "dev": true, 675 | "requires": { 676 | "is-glob": "^4.0.1" 677 | } 678 | }, 679 | "global-dirs": { 680 | "version": "2.0.1", 681 | "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.0.1.tgz", 682 | "integrity": "sha512-5HqUqdhkEovj2Of/ms3IeS/EekcO54ytHRLV4PEY2rhRwrHXLQjeVEES0Lhka0xwNDtGYn58wyC4s5+MHsOO6A==", 683 | "dev": true, 684 | "requires": { 685 | "ini": "^1.3.5" 686 | } 687 | }, 688 | "got": { 689 | "version": "9.6.0", 690 | "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", 691 | "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", 692 | "dev": true, 693 | "requires": { 694 | "@sindresorhus/is": "^0.14.0", 695 | "@szmarczak/http-timer": "^1.1.2", 696 | "cacheable-request": "^6.0.0", 697 | "decompress-response": "^3.3.0", 698 | "duplexer3": "^0.1.4", 699 | "get-stream": "^4.1.0", 700 | "lowercase-keys": "^1.0.1", 701 | "mimic-response": "^1.0.1", 702 | "p-cancelable": "^1.0.0", 703 | "to-readable-stream": "^1.0.0", 704 | "url-parse-lax": "^3.0.0" 705 | } 706 | }, 707 | "graceful-fs": { 708 | "version": "4.2.4", 709 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", 710 | "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", 711 | "dev": true 712 | }, 713 | "has-flag": { 714 | "version": "3.0.0", 715 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 716 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 717 | "dev": true 718 | }, 719 | "has-yarn": { 720 | "version": "2.1.0", 721 | "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", 722 | "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", 723 | "dev": true 724 | }, 725 | "helmet": { 726 | "version": "4.1.0", 727 | "resolved": "https://registry.npmjs.org/helmet/-/helmet-4.1.0.tgz", 728 | "integrity": "sha512-KWy75fYN8hOG2Rhl8e5B3WhOzb0by1boQum85TiddIE9iu6gV+TXbUjVC17wfej0o/ZUpqB9kxM0NFCZRMzf+Q==" 729 | }, 730 | "http-cache-semantics": { 731 | "version": "4.1.0", 732 | "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", 733 | "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", 734 | "dev": true 735 | }, 736 | "http-errors": { 737 | "version": "1.7.2", 738 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", 739 | "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", 740 | "requires": { 741 | "depd": "~1.1.2", 742 | "inherits": "2.0.3", 743 | "setprototypeof": "1.1.1", 744 | "statuses": ">= 1.5.0 < 2", 745 | "toidentifier": "1.0.0" 746 | } 747 | }, 748 | "iconv-lite": { 749 | "version": "0.4.24", 750 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 751 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 752 | "requires": { 753 | "safer-buffer": ">= 2.1.2 < 3" 754 | } 755 | }, 756 | "ignore-by-default": { 757 | "version": "1.0.1", 758 | "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", 759 | "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", 760 | "dev": true 761 | }, 762 | "import-lazy": { 763 | "version": "2.1.0", 764 | "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", 765 | "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", 766 | "dev": true 767 | }, 768 | "imurmurhash": { 769 | "version": "0.1.4", 770 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 771 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", 772 | "dev": true 773 | }, 774 | "inherits": { 775 | "version": "2.0.3", 776 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 777 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 778 | }, 779 | "ini": { 780 | "version": "1.3.5", 781 | "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", 782 | "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", 783 | "dev": true 784 | }, 785 | "ipaddr.js": { 786 | "version": "1.9.1", 787 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 788 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" 789 | }, 790 | "is-binary-path": { 791 | "version": "2.1.0", 792 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 793 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 794 | "dev": true, 795 | "requires": { 796 | "binary-extensions": "^2.0.0" 797 | } 798 | }, 799 | "is-ci": { 800 | "version": "2.0.0", 801 | "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", 802 | "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", 803 | "dev": true, 804 | "requires": { 805 | "ci-info": "^2.0.0" 806 | } 807 | }, 808 | "is-extglob": { 809 | "version": "2.1.1", 810 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 811 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", 812 | "dev": true 813 | }, 814 | "is-fullwidth-code-point": { 815 | "version": "2.0.0", 816 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 817 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 818 | "dev": true 819 | }, 820 | "is-glob": { 821 | "version": "4.0.1", 822 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", 823 | "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", 824 | "dev": true, 825 | "requires": { 826 | "is-extglob": "^2.1.1" 827 | } 828 | }, 829 | "is-installed-globally": { 830 | "version": "0.3.2", 831 | "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", 832 | "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", 833 | "dev": true, 834 | "requires": { 835 | "global-dirs": "^2.0.1", 836 | "is-path-inside": "^3.0.1" 837 | } 838 | }, 839 | "is-npm": { 840 | "version": "4.0.0", 841 | "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", 842 | "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==", 843 | "dev": true 844 | }, 845 | "is-number": { 846 | "version": "7.0.0", 847 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 848 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 849 | "dev": true 850 | }, 851 | "is-obj": { 852 | "version": "2.0.0", 853 | "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", 854 | "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", 855 | "dev": true 856 | }, 857 | "is-path-inside": { 858 | "version": "3.0.2", 859 | "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.2.tgz", 860 | "integrity": "sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==", 861 | "dev": true 862 | }, 863 | "is-typedarray": { 864 | "version": "1.0.0", 865 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", 866 | "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", 867 | "dev": true 868 | }, 869 | "is-yarn-global": { 870 | "version": "0.3.0", 871 | "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", 872 | "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", 873 | "dev": true 874 | }, 875 | "json-buffer": { 876 | "version": "3.0.0", 877 | "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", 878 | "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", 879 | "dev": true 880 | }, 881 | "jsonwebtoken": { 882 | "version": "8.5.1", 883 | "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", 884 | "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", 885 | "requires": { 886 | "jws": "^3.2.2", 887 | "lodash.includes": "^4.3.0", 888 | "lodash.isboolean": "^3.0.3", 889 | "lodash.isinteger": "^4.0.4", 890 | "lodash.isnumber": "^3.0.3", 891 | "lodash.isplainobject": "^4.0.6", 892 | "lodash.isstring": "^4.0.1", 893 | "lodash.once": "^4.0.0", 894 | "ms": "^2.1.1", 895 | "semver": "^5.6.0" 896 | }, 897 | "dependencies": { 898 | "ms": { 899 | "version": "2.1.2", 900 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 901 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 902 | } 903 | } 904 | }, 905 | "jwa": { 906 | "version": "1.4.1", 907 | "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", 908 | "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", 909 | "requires": { 910 | "buffer-equal-constant-time": "1.0.1", 911 | "ecdsa-sig-formatter": "1.0.11", 912 | "safe-buffer": "^5.0.1" 913 | } 914 | }, 915 | "jwks-rsa": { 916 | "version": "1.9.0", 917 | "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-1.9.0.tgz", 918 | "integrity": "sha512-UPCfQQg0s2kF2Ju6UFJrQH73f7MaVN/hKBnYBYOp+X9KN4y6TLChhLtaXS5nRKbZqshwVdrZ9OY63m/Q9CLqcg==", 919 | "requires": { 920 | "@types/express-jwt": "0.0.42", 921 | "axios": "^0.19.2", 922 | "debug": "^4.1.0", 923 | "jsonwebtoken": "^8.5.1", 924 | "limiter": "^1.1.5", 925 | "lru-memoizer": "^2.1.2", 926 | "ms": "^2.1.2" 927 | }, 928 | "dependencies": { 929 | "debug": { 930 | "version": "4.1.1", 931 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", 932 | "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", 933 | "requires": { 934 | "ms": "^2.1.1" 935 | } 936 | }, 937 | "ms": { 938 | "version": "2.1.2", 939 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 940 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 941 | } 942 | } 943 | }, 944 | "jws": { 945 | "version": "3.2.2", 946 | "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", 947 | "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", 948 | "requires": { 949 | "jwa": "^1.4.1", 950 | "safe-buffer": "^5.0.1" 951 | } 952 | }, 953 | "keyv": { 954 | "version": "3.1.0", 955 | "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", 956 | "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", 957 | "dev": true, 958 | "requires": { 959 | "json-buffer": "3.0.0" 960 | } 961 | }, 962 | "latest-version": { 963 | "version": "5.1.0", 964 | "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", 965 | "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", 966 | "dev": true, 967 | "requires": { 968 | "package-json": "^6.3.0" 969 | } 970 | }, 971 | "limiter": { 972 | "version": "1.1.5", 973 | "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", 974 | "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==" 975 | }, 976 | "lodash.clonedeep": { 977 | "version": "4.5.0", 978 | "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", 979 | "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" 980 | }, 981 | "lodash.includes": { 982 | "version": "4.3.0", 983 | "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", 984 | "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" 985 | }, 986 | "lodash.isboolean": { 987 | "version": "3.0.3", 988 | "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", 989 | "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" 990 | }, 991 | "lodash.isinteger": { 992 | "version": "4.0.4", 993 | "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", 994 | "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" 995 | }, 996 | "lodash.isnumber": { 997 | "version": "3.0.3", 998 | "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", 999 | "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" 1000 | }, 1001 | "lodash.isplainobject": { 1002 | "version": "4.0.6", 1003 | "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", 1004 | "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" 1005 | }, 1006 | "lodash.isstring": { 1007 | "version": "4.0.1", 1008 | "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", 1009 | "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" 1010 | }, 1011 | "lodash.once": { 1012 | "version": "4.1.1", 1013 | "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", 1014 | "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" 1015 | }, 1016 | "lodash.set": { 1017 | "version": "4.3.2", 1018 | "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", 1019 | "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=" 1020 | }, 1021 | "lowercase-keys": { 1022 | "version": "1.0.1", 1023 | "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", 1024 | "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", 1025 | "dev": true 1026 | }, 1027 | "lru-cache": { 1028 | "version": "4.0.2", 1029 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz", 1030 | "integrity": "sha1-HRdnnAac2l0ECZGgnbwsDbN35V4=", 1031 | "requires": { 1032 | "pseudomap": "^1.0.1", 1033 | "yallist": "^2.0.0" 1034 | } 1035 | }, 1036 | "lru-memoizer": { 1037 | "version": "2.1.2", 1038 | "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.1.2.tgz", 1039 | "integrity": "sha512-N5L5xlnVcbIinNn/TJ17vHBZwBMt9t7aJDz2n97moWubjNl6VO9Ao2XuAGBBddkYdjrwR9HfzXbT6NfMZXAZ/A==", 1040 | "requires": { 1041 | "lodash.clonedeep": "^4.5.0", 1042 | "lru-cache": "~4.0.0" 1043 | } 1044 | }, 1045 | "make-dir": { 1046 | "version": "3.1.0", 1047 | "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", 1048 | "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", 1049 | "dev": true, 1050 | "requires": { 1051 | "semver": "^6.0.0" 1052 | }, 1053 | "dependencies": { 1054 | "semver": { 1055 | "version": "6.3.0", 1056 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", 1057 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", 1058 | "dev": true 1059 | } 1060 | } 1061 | }, 1062 | "media-typer": { 1063 | "version": "0.3.0", 1064 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 1065 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 1066 | }, 1067 | "merge-descriptors": { 1068 | "version": "1.0.1", 1069 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 1070 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 1071 | }, 1072 | "methods": { 1073 | "version": "1.1.2", 1074 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 1075 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 1076 | }, 1077 | "mime": { 1078 | "version": "1.6.0", 1079 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 1080 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" 1081 | }, 1082 | "mime-db": { 1083 | "version": "1.44.0", 1084 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", 1085 | "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" 1086 | }, 1087 | "mime-types": { 1088 | "version": "2.1.27", 1089 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", 1090 | "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", 1091 | "requires": { 1092 | "mime-db": "1.44.0" 1093 | } 1094 | }, 1095 | "mimic-response": { 1096 | "version": "1.0.1", 1097 | "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", 1098 | "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", 1099 | "dev": true 1100 | }, 1101 | "minimatch": { 1102 | "version": "3.0.4", 1103 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 1104 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 1105 | "dev": true, 1106 | "requires": { 1107 | "brace-expansion": "^1.1.7" 1108 | } 1109 | }, 1110 | "minimist": { 1111 | "version": "1.2.5", 1112 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", 1113 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", 1114 | "dev": true 1115 | }, 1116 | "ms": { 1117 | "version": "2.0.0", 1118 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 1119 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 1120 | }, 1121 | "negotiator": { 1122 | "version": "0.6.2", 1123 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", 1124 | "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" 1125 | }, 1126 | "nodemon": { 1127 | "version": "2.0.4", 1128 | "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.4.tgz", 1129 | "integrity": "sha512-Ltced+hIfTmaS28Zjv1BM552oQ3dbwPqI4+zI0SLgq+wpJhSyqgYude/aZa/3i31VCQWMfXJVxvu86abcam3uQ==", 1130 | "dev": true, 1131 | "requires": { 1132 | "chokidar": "^3.2.2", 1133 | "debug": "^3.2.6", 1134 | "ignore-by-default": "^1.0.1", 1135 | "minimatch": "^3.0.4", 1136 | "pstree.remy": "^1.1.7", 1137 | "semver": "^5.7.1", 1138 | "supports-color": "^5.5.0", 1139 | "touch": "^3.1.0", 1140 | "undefsafe": "^2.0.2", 1141 | "update-notifier": "^4.0.0" 1142 | }, 1143 | "dependencies": { 1144 | "debug": { 1145 | "version": "3.2.6", 1146 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", 1147 | "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", 1148 | "dev": true, 1149 | "requires": { 1150 | "ms": "^2.1.1" 1151 | } 1152 | }, 1153 | "ms": { 1154 | "version": "2.1.2", 1155 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 1156 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 1157 | "dev": true 1158 | } 1159 | } 1160 | }, 1161 | "nopt": { 1162 | "version": "1.0.10", 1163 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", 1164 | "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", 1165 | "dev": true, 1166 | "requires": { 1167 | "abbrev": "1" 1168 | } 1169 | }, 1170 | "normalize-path": { 1171 | "version": "3.0.0", 1172 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 1173 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 1174 | "dev": true 1175 | }, 1176 | "normalize-url": { 1177 | "version": "4.5.0", 1178 | "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", 1179 | "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==", 1180 | "dev": true 1181 | }, 1182 | "object-assign": { 1183 | "version": "4.1.1", 1184 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 1185 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" 1186 | }, 1187 | "on-finished": { 1188 | "version": "2.3.0", 1189 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 1190 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 1191 | "requires": { 1192 | "ee-first": "1.1.1" 1193 | } 1194 | }, 1195 | "once": { 1196 | "version": "1.4.0", 1197 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1198 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 1199 | "dev": true, 1200 | "requires": { 1201 | "wrappy": "1" 1202 | } 1203 | }, 1204 | "p-cancelable": { 1205 | "version": "1.1.0", 1206 | "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", 1207 | "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", 1208 | "dev": true 1209 | }, 1210 | "package-json": { 1211 | "version": "6.5.0", 1212 | "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", 1213 | "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", 1214 | "dev": true, 1215 | "requires": { 1216 | "got": "^9.6.0", 1217 | "registry-auth-token": "^4.0.0", 1218 | "registry-url": "^5.0.0", 1219 | "semver": "^6.2.0" 1220 | }, 1221 | "dependencies": { 1222 | "semver": { 1223 | "version": "6.3.0", 1224 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", 1225 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", 1226 | "dev": true 1227 | } 1228 | } 1229 | }, 1230 | "parseurl": { 1231 | "version": "1.3.3", 1232 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 1233 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" 1234 | }, 1235 | "path-to-regexp": { 1236 | "version": "0.1.7", 1237 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 1238 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 1239 | }, 1240 | "picomatch": { 1241 | "version": "2.2.2", 1242 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", 1243 | "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", 1244 | "dev": true 1245 | }, 1246 | "prepend-http": { 1247 | "version": "2.0.0", 1248 | "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", 1249 | "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", 1250 | "dev": true 1251 | }, 1252 | "prettier": { 1253 | "version": "2.1.1", 1254 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.1.1.tgz", 1255 | "integrity": "sha512-9bY+5ZWCfqj3ghYBLxApy2zf6m+NJo5GzmLTpr9FsApsfjriNnS2dahWReHMi7qNPhhHl9SYHJs2cHZLgexNIw==", 1256 | "dev": true 1257 | }, 1258 | "proxy-addr": { 1259 | "version": "2.0.6", 1260 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", 1261 | "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", 1262 | "requires": { 1263 | "forwarded": "~0.1.2", 1264 | "ipaddr.js": "1.9.1" 1265 | } 1266 | }, 1267 | "pseudomap": { 1268 | "version": "1.0.2", 1269 | "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", 1270 | "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" 1271 | }, 1272 | "pstree.remy": { 1273 | "version": "1.1.8", 1274 | "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", 1275 | "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", 1276 | "dev": true 1277 | }, 1278 | "pump": { 1279 | "version": "3.0.0", 1280 | "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", 1281 | "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", 1282 | "dev": true, 1283 | "requires": { 1284 | "end-of-stream": "^1.1.0", 1285 | "once": "^1.3.1" 1286 | } 1287 | }, 1288 | "pupa": { 1289 | "version": "2.0.1", 1290 | "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.0.1.tgz", 1291 | "integrity": "sha512-hEJH0s8PXLY/cdXh66tNEQGndDrIKNqNC5xmrysZy3i5C3oEoLna7YAOad+7u125+zH1HNXUmGEkrhb3c2VriA==", 1292 | "dev": true, 1293 | "requires": { 1294 | "escape-goat": "^2.0.0" 1295 | } 1296 | }, 1297 | "qs": { 1298 | "version": "6.7.0", 1299 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", 1300 | "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" 1301 | }, 1302 | "range-parser": { 1303 | "version": "1.2.1", 1304 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 1305 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" 1306 | }, 1307 | "raw-body": { 1308 | "version": "2.4.0", 1309 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", 1310 | "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", 1311 | "requires": { 1312 | "bytes": "3.1.0", 1313 | "http-errors": "1.7.2", 1314 | "iconv-lite": "0.4.24", 1315 | "unpipe": "1.0.0" 1316 | } 1317 | }, 1318 | "rc": { 1319 | "version": "1.2.8", 1320 | "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", 1321 | "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", 1322 | "dev": true, 1323 | "requires": { 1324 | "deep-extend": "^0.6.0", 1325 | "ini": "~1.3.0", 1326 | "minimist": "^1.2.0", 1327 | "strip-json-comments": "~2.0.1" 1328 | } 1329 | }, 1330 | "readdirp": { 1331 | "version": "3.4.0", 1332 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz", 1333 | "integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==", 1334 | "dev": true, 1335 | "requires": { 1336 | "picomatch": "^2.2.1" 1337 | } 1338 | }, 1339 | "registry-auth-token": { 1340 | "version": "4.2.0", 1341 | "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.0.tgz", 1342 | "integrity": "sha512-P+lWzPrsgfN+UEpDS3U8AQKg/UjZX6mQSJueZj3EK+vNESoqBSpBUD3gmu4sF9lOsjXWjF11dQKUqemf3veq1w==", 1343 | "dev": true, 1344 | "requires": { 1345 | "rc": "^1.2.8" 1346 | } 1347 | }, 1348 | "registry-url": { 1349 | "version": "5.1.0", 1350 | "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", 1351 | "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", 1352 | "dev": true, 1353 | "requires": { 1354 | "rc": "^1.2.8" 1355 | } 1356 | }, 1357 | "responselike": { 1358 | "version": "1.0.2", 1359 | "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", 1360 | "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", 1361 | "dev": true, 1362 | "requires": { 1363 | "lowercase-keys": "^1.0.0" 1364 | } 1365 | }, 1366 | "safe-buffer": { 1367 | "version": "5.1.2", 1368 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 1369 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 1370 | }, 1371 | "safer-buffer": { 1372 | "version": "2.1.2", 1373 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 1374 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 1375 | }, 1376 | "semver": { 1377 | "version": "5.7.1", 1378 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 1379 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" 1380 | }, 1381 | "semver-diff": { 1382 | "version": "3.1.1", 1383 | "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", 1384 | "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", 1385 | "dev": true, 1386 | "requires": { 1387 | "semver": "^6.3.0" 1388 | }, 1389 | "dependencies": { 1390 | "semver": { 1391 | "version": "6.3.0", 1392 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", 1393 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", 1394 | "dev": true 1395 | } 1396 | } 1397 | }, 1398 | "send": { 1399 | "version": "0.17.1", 1400 | "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", 1401 | "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", 1402 | "requires": { 1403 | "debug": "2.6.9", 1404 | "depd": "~1.1.2", 1405 | "destroy": "~1.0.4", 1406 | "encodeurl": "~1.0.2", 1407 | "escape-html": "~1.0.3", 1408 | "etag": "~1.8.1", 1409 | "fresh": "0.5.2", 1410 | "http-errors": "~1.7.2", 1411 | "mime": "1.6.0", 1412 | "ms": "2.1.1", 1413 | "on-finished": "~2.3.0", 1414 | "range-parser": "~1.2.1", 1415 | "statuses": "~1.5.0" 1416 | }, 1417 | "dependencies": { 1418 | "ms": { 1419 | "version": "2.1.1", 1420 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", 1421 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" 1422 | } 1423 | } 1424 | }, 1425 | "serve-static": { 1426 | "version": "1.14.1", 1427 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", 1428 | "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", 1429 | "requires": { 1430 | "encodeurl": "~1.0.2", 1431 | "escape-html": "~1.0.3", 1432 | "parseurl": "~1.3.3", 1433 | "send": "0.17.1" 1434 | } 1435 | }, 1436 | "setprototypeof": { 1437 | "version": "1.1.1", 1438 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", 1439 | "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" 1440 | }, 1441 | "signal-exit": { 1442 | "version": "3.0.3", 1443 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", 1444 | "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", 1445 | "dev": true 1446 | }, 1447 | "statuses": { 1448 | "version": "1.5.0", 1449 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", 1450 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" 1451 | }, 1452 | "string-width": { 1453 | "version": "4.2.0", 1454 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", 1455 | "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", 1456 | "dev": true, 1457 | "requires": { 1458 | "emoji-regex": "^8.0.0", 1459 | "is-fullwidth-code-point": "^3.0.0", 1460 | "strip-ansi": "^6.0.0" 1461 | }, 1462 | "dependencies": { 1463 | "ansi-regex": { 1464 | "version": "5.0.0", 1465 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", 1466 | "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", 1467 | "dev": true 1468 | }, 1469 | "emoji-regex": { 1470 | "version": "8.0.0", 1471 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 1472 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 1473 | "dev": true 1474 | }, 1475 | "is-fullwidth-code-point": { 1476 | "version": "3.0.0", 1477 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 1478 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 1479 | "dev": true 1480 | }, 1481 | "strip-ansi": { 1482 | "version": "6.0.0", 1483 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", 1484 | "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", 1485 | "dev": true, 1486 | "requires": { 1487 | "ansi-regex": "^5.0.0" 1488 | } 1489 | } 1490 | } 1491 | }, 1492 | "strip-ansi": { 1493 | "version": "5.2.0", 1494 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", 1495 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", 1496 | "dev": true, 1497 | "requires": { 1498 | "ansi-regex": "^4.1.0" 1499 | } 1500 | }, 1501 | "strip-json-comments": { 1502 | "version": "2.0.1", 1503 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 1504 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", 1505 | "dev": true 1506 | }, 1507 | "supports-color": { 1508 | "version": "5.5.0", 1509 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 1510 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 1511 | "dev": true, 1512 | "requires": { 1513 | "has-flag": "^3.0.0" 1514 | } 1515 | }, 1516 | "term-size": { 1517 | "version": "2.2.0", 1518 | "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.0.tgz", 1519 | "integrity": "sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw==", 1520 | "dev": true 1521 | }, 1522 | "to-readable-stream": { 1523 | "version": "1.0.0", 1524 | "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", 1525 | "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", 1526 | "dev": true 1527 | }, 1528 | "to-regex-range": { 1529 | "version": "5.0.1", 1530 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1531 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1532 | "dev": true, 1533 | "requires": { 1534 | "is-number": "^7.0.0" 1535 | } 1536 | }, 1537 | "toidentifier": { 1538 | "version": "1.0.0", 1539 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", 1540 | "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" 1541 | }, 1542 | "touch": { 1543 | "version": "3.1.0", 1544 | "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", 1545 | "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", 1546 | "dev": true, 1547 | "requires": { 1548 | "nopt": "~1.0.10" 1549 | } 1550 | }, 1551 | "type-fest": { 1552 | "version": "0.8.1", 1553 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", 1554 | "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", 1555 | "dev": true 1556 | }, 1557 | "type-is": { 1558 | "version": "1.6.18", 1559 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 1560 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 1561 | "requires": { 1562 | "media-typer": "0.3.0", 1563 | "mime-types": "~2.1.24" 1564 | } 1565 | }, 1566 | "typedarray-to-buffer": { 1567 | "version": "3.1.5", 1568 | "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", 1569 | "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", 1570 | "dev": true, 1571 | "requires": { 1572 | "is-typedarray": "^1.0.0" 1573 | } 1574 | }, 1575 | "undefsafe": { 1576 | "version": "2.0.3", 1577 | "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", 1578 | "integrity": "sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A==", 1579 | "dev": true, 1580 | "requires": { 1581 | "debug": "^2.2.0" 1582 | } 1583 | }, 1584 | "unique-string": { 1585 | "version": "2.0.0", 1586 | "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", 1587 | "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", 1588 | "dev": true, 1589 | "requires": { 1590 | "crypto-random-string": "^2.0.0" 1591 | } 1592 | }, 1593 | "unpipe": { 1594 | "version": "1.0.0", 1595 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 1596 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 1597 | }, 1598 | "update-notifier": { 1599 | "version": "4.1.1", 1600 | "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.1.tgz", 1601 | "integrity": "sha512-9y+Kds0+LoLG6yN802wVXoIfxYEwh3FlZwzMwpCZp62S2i1/Jzeqb9Eeeju3NSHccGGasfGlK5/vEHbAifYRDg==", 1602 | "dev": true, 1603 | "requires": { 1604 | "boxen": "^4.2.0", 1605 | "chalk": "^3.0.0", 1606 | "configstore": "^5.0.1", 1607 | "has-yarn": "^2.1.0", 1608 | "import-lazy": "^2.1.0", 1609 | "is-ci": "^2.0.0", 1610 | "is-installed-globally": "^0.3.1", 1611 | "is-npm": "^4.0.0", 1612 | "is-yarn-global": "^0.3.0", 1613 | "latest-version": "^5.0.0", 1614 | "pupa": "^2.0.1", 1615 | "semver-diff": "^3.1.1", 1616 | "xdg-basedir": "^4.0.0" 1617 | } 1618 | }, 1619 | "url-parse-lax": { 1620 | "version": "3.0.0", 1621 | "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", 1622 | "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", 1623 | "dev": true, 1624 | "requires": { 1625 | "prepend-http": "^2.0.0" 1626 | } 1627 | }, 1628 | "utils-merge": { 1629 | "version": "1.0.1", 1630 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 1631 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 1632 | }, 1633 | "vary": { 1634 | "version": "1.1.2", 1635 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 1636 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 1637 | }, 1638 | "widest-line": { 1639 | "version": "3.1.0", 1640 | "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", 1641 | "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", 1642 | "dev": true, 1643 | "requires": { 1644 | "string-width": "^4.0.0" 1645 | } 1646 | }, 1647 | "wrappy": { 1648 | "version": "1.0.2", 1649 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1650 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 1651 | "dev": true 1652 | }, 1653 | "write-file-atomic": { 1654 | "version": "3.0.3", 1655 | "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", 1656 | "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", 1657 | "dev": true, 1658 | "requires": { 1659 | "imurmurhash": "^0.1.4", 1660 | "is-typedarray": "^1.0.0", 1661 | "signal-exit": "^3.0.2", 1662 | "typedarray-to-buffer": "^3.1.5" 1663 | } 1664 | }, 1665 | "xdg-basedir": { 1666 | "version": "4.0.0", 1667 | "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", 1668 | "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", 1669 | "dev": true 1670 | }, 1671 | "yallist": { 1672 | "version": "2.1.2", 1673 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", 1674 | "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" 1675 | } 1676 | } 1677 | } 1678 | -------------------------------------------------------------------------------- /backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-express-js", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "nodemon src/index.js", 8 | "start": "node src/index.js" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "cors": "^2.8.5", 15 | "dotenv": "^8.2.0", 16 | "express": "^4.17.1", 17 | "express-jwt": "^6.0.0", 18 | "helmet": "^4.1.0", 19 | "jwks-rsa": "^1.9.0" 20 | }, 21 | "devDependencies": { 22 | "nodemon": "^2.0.4", 23 | "prettier": "^2.1.1" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /backend/src/authz/check-jwt.js: -------------------------------------------------------------------------------- 1 | const jwt = require('express-jwt'); 2 | const jwksRsa = require('jwks-rsa'); 3 | const { domain, audience } = require('../config/env.dev'); 4 | 5 | const checkJwt = jwt({ 6 | secret: jwksRsa.expressJwtSecret({ 7 | cache: true, 8 | rateLimit: true, 9 | jwksRequestsPerMinute: 5, 10 | jwksUri: `https://${domain}/.well-known/jwks.json`, 11 | }), 12 | 13 | audience: audience, 14 | issuer: `https://${domain}/`, 15 | algorithms: ['RS256'], 16 | }); 17 | 18 | module.exports = { 19 | checkJwt, 20 | }; 21 | -------------------------------------------------------------------------------- /backend/src/config/env.dev.js: -------------------------------------------------------------------------------- 1 | const dotenv = require('dotenv'); 2 | 3 | dotenv.config(); 4 | 5 | const audience = process.env.AUTH0_AUDIENCE; 6 | const domain = process.env.AUTH0_DOMAIN; 7 | const serverPort = process.env.SERVER_PORT; 8 | const clientOriginUrl = process.env.CLIENT_ORIGIN_URL; 9 | 10 | if (!audience) { 11 | throw new Error( 12 | '.env is missing the definition of an AUTH0_AUDIENCE environmental variable' 13 | ); 14 | } 15 | 16 | if (!domain) { 17 | throw new Error( 18 | '.env is missing the definition of an AUTH0_DOMAIN environmental variable' 19 | ); 20 | } 21 | 22 | if (!serverPort) { 23 | throw new Error( 24 | '.env is missing the definition of a API_PORT environmental variable' 25 | ); 26 | } 27 | 28 | if (!clientOriginUrl) { 29 | throw new Error( 30 | '.env is missing the definition of a APP_ORIGIN environmental variable' 31 | ); 32 | } 33 | 34 | const clientOrigins = ['http://localhost:4040']; 35 | 36 | module.exports = { 37 | audience, 38 | domain, 39 | serverPort, 40 | clientOriginUrl, 41 | clientOrigins, 42 | }; 43 | -------------------------------------------------------------------------------- /backend/src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Required External Modules 3 | */ 4 | 5 | const express = require("express"); 6 | const cors = require("cors"); 7 | const helmet = require("helmet"); 8 | const { clientOrigins, serverPort } = require("./config/env.dev"); 9 | 10 | const { messagesRouter } = require("./messages/messages.router"); 11 | 12 | /** 13 | * App Variables 14 | */ 15 | 16 | const app = express(); 17 | const apiRouter = express.Router(); 18 | 19 | /** 20 | * App Configuration 21 | */ 22 | 23 | app.use(helmet()); 24 | app.use(cors({ origin: clientOrigins })); 25 | app.use(express.json()); 26 | 27 | app.use("/api", apiRouter); 28 | 29 | apiRouter.use("/messages", messagesRouter); 30 | 31 | app.use(function (err, req, res, next) { 32 | console.log(err); 33 | res.status(500).send(err.message); 34 | }); 35 | 36 | /** 37 | * Server Activation 38 | */ 39 | 40 | app.listen(serverPort, () => 41 | console.log(`API Server listening on port ${serverPort}`) 42 | ); 43 | -------------------------------------------------------------------------------- /backend/src/messages/messages.router.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Required External Modules and Interfaces 3 | */ 4 | 5 | const express = require("express"); 6 | const { getPublicMessage, getProtectedMessage } = require("./messages.service"); 7 | const { checkJwt } = require("../authz/check-jwt"); 8 | 9 | /** 10 | * Router Definition 11 | */ 12 | 13 | const messagesRouter = express.Router(); 14 | 15 | /** 16 | * Controller Definitions 17 | */ 18 | 19 | // GET messages/ 20 | 21 | messagesRouter.get("/public-message", (req, res) => { 22 | const message = getPublicMessage(); 23 | res.status(200).send(message); 24 | }); 25 | 26 | messagesRouter.get("/protected-message", checkJwt, (req, res) => { 27 | const message = getProtectedMessage(); 28 | res.status(200).send(message); 29 | }); 30 | 31 | module.exports = { 32 | messagesRouter, 33 | }; 34 | -------------------------------------------------------------------------------- /backend/src/messages/messages.service.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Service Methods 3 | */ 4 | 5 | const getPublicMessage = () => { 6 | return { 7 | message: "The API doesn't require an access token to share this message.", 8 | }; 9 | }; 10 | 11 | const getProtectedMessage = () => { 12 | return { 13 | message: "The API successfully validated your access token.", 14 | }; 15 | }; 16 | 17 | module.exports = { 18 | getPublicMessage, 19 | getProtectedMessage, 20 | }; 21 | -------------------------------------------------------------------------------- /frontend/.env.example: -------------------------------------------------------------------------------- 1 | REACT_APP_AUTH0_DOMAIN= 2 | REACT_APP_AUTH0_CLIENT_ID= 3 | REACT_APP_AUTH0_AUDIENCE= 4 | REACT_APP_SERVER_URL= -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/node,linux,macos,windows,intellij,webstorm,jetbrains,visualstudio,visualstudiocode 3 | # Edit at https://www.gitignore.io/?templates=node,linux,macos,windows,intellij,webstorm,jetbrains,visualstudio,visualstudiocode 4 | 5 | ### Intellij ### 6 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 7 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 8 | 9 | # User-specific stuff 10 | .idea/**/workspace.xml 11 | .idea/**/tasks.xml 12 | .idea/**/usage.statistics.xml 13 | .idea/**/dictionaries 14 | .idea/**/shelf 15 | 16 | # Generated files 17 | .idea/**/contentModel.xml 18 | 19 | # Sensitive or high-churn files 20 | .idea/**/dataSources/ 21 | .idea/**/dataSources.ids 22 | .idea/**/dataSources.local.xml 23 | .idea/**/sqlDataSources.xml 24 | .idea/**/dynamic.xml 25 | .idea/**/uiDesigner.xml 26 | .idea/**/dbnavigator.xml 27 | 28 | # Gradle 29 | .idea/**/gradle.xml 30 | .idea/**/libraries 31 | 32 | # Gradle and Maven with auto-import 33 | # When using Gradle or Maven with auto-import, you should exclude module files, 34 | # since they will be recreated, and may cause churn. Uncomment if using 35 | # auto-import. 36 | # .idea/modules.xml 37 | # .idea/*.iml 38 | # .idea/modules 39 | 40 | # CMake 41 | cmake-build-*/ 42 | 43 | # Mongo Explorer plugin 44 | .idea/**/mongoSettings.xml 45 | 46 | # File-based project format 47 | *.iws 48 | 49 | # IntelliJ 50 | out/ 51 | 52 | # mpeltonen/sbt-idea plugin 53 | .idea_modules/ 54 | 55 | # JIRA plugin 56 | atlassian-ide-plugin.xml 57 | 58 | # Cursive Clojure plugin 59 | .idea/replstate.xml 60 | 61 | # Crashlytics plugin (for Android Studio and IntelliJ) 62 | com_crashlytics_export_strings.xml 63 | crashlytics.properties 64 | crashlytics-build.properties 65 | fabric.properties 66 | 67 | # Editor-based Rest Client 68 | .idea/httpRequests 69 | 70 | # Android studio 3.1+ serialized cache file 71 | .idea/caches/build_file_checksums.ser 72 | 73 | # JetBrains templates 74 | **___jb_tmp___ 75 | 76 | ### Intellij Patch ### 77 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 78 | 79 | # *.iml 80 | # modules.xml 81 | # .idea/misc.xml 82 | # *.ipr 83 | 84 | # Sonarlint plugin 85 | .idea/sonarlint 86 | 87 | ### JetBrains ### 88 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 89 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 90 | 91 | # User-specific stuff 92 | 93 | # Generated files 94 | 95 | # Sensitive or high-churn files 96 | 97 | # Gradle 98 | 99 | # Gradle and Maven with auto-import 100 | # When using Gradle or Maven with auto-import, you should exclude module files, 101 | # since they will be recreated, and may cause churn. Uncomment if using 102 | # auto-import. 103 | # .idea/modules.xml 104 | # .idea/*.iml 105 | # .idea/modules 106 | 107 | # CMake 108 | 109 | # Mongo Explorer plugin 110 | 111 | # File-based project format 112 | 113 | # IntelliJ 114 | 115 | # mpeltonen/sbt-idea plugin 116 | 117 | # JIRA plugin 118 | 119 | # Cursive Clojure plugin 120 | 121 | # Crashlytics plugin (for Android Studio and IntelliJ) 122 | 123 | # Editor-based Rest Client 124 | 125 | # Android studio 3.1+ serialized cache file 126 | 127 | # JetBrains templates 128 | 129 | ### JetBrains Patch ### 130 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 131 | 132 | # *.iml 133 | # modules.xml 134 | # .idea/misc.xml 135 | # *.ipr 136 | 137 | # Sonarlint plugin 138 | 139 | ### Linux ### 140 | *~ 141 | 142 | # temporary files which can be created if a process still has a handle open of a deleted file 143 | .fuse_hidden* 144 | 145 | # KDE directory preferences 146 | .directory 147 | 148 | # Linux trash folder which might appear on any partition or disk 149 | .Trash-* 150 | 151 | # .nfs files are created when an open file is removed but is still being accessed 152 | .nfs* 153 | 154 | ### macOS ### 155 | # General 156 | .DS_Store 157 | .AppleDouble 158 | .LSOverride 159 | 160 | # Icon must end with two \r 161 | Icon 162 | 163 | # Thumbnails 164 | ._* 165 | 166 | # Files that might appear in the root of a volume 167 | .DocumentRevisions-V100 168 | .fseventsd 169 | .Spotlight-V100 170 | .TemporaryItems 171 | .Trashes 172 | .VolumeIcon.icns 173 | .com.apple.timemachine.donotpresent 174 | 175 | # Directories potentially created on remote AFP share 176 | .AppleDB 177 | .AppleDesktop 178 | Network Trash Folder 179 | Temporary Items 180 | .apdisk 181 | 182 | ### Node ### 183 | # Logs 184 | logs 185 | *.log 186 | npm-debug.log* 187 | yarn-debug.log* 188 | yarn-error.log* 189 | lerna-debug.log* 190 | 191 | # Diagnostic reports (https://nodejs.org/api/report.html) 192 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 193 | 194 | # Runtime data 195 | pids 196 | *.pid 197 | *.seed 198 | *.pid.lock 199 | 200 | # Directory for instrumented libs generated by jscoverage/JSCover 201 | lib-cov 202 | 203 | # Coverage directory used by tools like istanbul 204 | coverage 205 | 206 | # nyc test coverage 207 | .nyc_output 208 | 209 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 210 | .grunt 211 | 212 | # Bower dependency directory (https://bower.io/) 213 | bower_components 214 | 215 | # node-waf configuration 216 | .lock-wscript 217 | 218 | # Compiled binary addons (https://nodejs.org/api/addons.html) 219 | build/Release 220 | 221 | # Dependency directories 222 | node_modules/ 223 | jspm_packages/ 224 | 225 | # TypeScript v1 declaration files 226 | typings/ 227 | 228 | # Optional npm cache directory 229 | .npm 230 | 231 | # Optional eslint cache 232 | .eslintcache 233 | 234 | # Optional REPL history 235 | .node_repl_history 236 | 237 | # Output of 'npm pack' 238 | *.tgz 239 | 240 | # Yarn Integrity file 241 | .yarn-integrity 242 | 243 | # dotenv environment variables file 244 | .env 245 | .env.test 246 | 247 | # parcel-bundler cache (https://parceljs.org/) 248 | .cache 249 | 250 | # next.js build output 251 | .next 252 | 253 | # nuxt.js build output 254 | .nuxt 255 | 256 | # vuepress build output 257 | .vuepress/dist 258 | 259 | # Serverless directories 260 | .serverless/ 261 | 262 | # FuseBox cache 263 | .fusebox/ 264 | 265 | # DynamoDB Local files 266 | .dynamodb/ 267 | 268 | ### VisualStudioCode ### 269 | .vscode/* 270 | !.vscode/settings.json 271 | !.vscode/tasks.json 272 | !.vscode/launch.json 273 | !.vscode/extensions.json 274 | 275 | ### VisualStudioCode Patch ### 276 | # Ignore all local history of files 277 | .history 278 | 279 | ### WebStorm ### 280 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 281 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 282 | 283 | # User-specific stuff 284 | 285 | # Generated files 286 | 287 | # Sensitive or high-churn files 288 | 289 | # Gradle 290 | 291 | # Gradle and Maven with auto-import 292 | # When using Gradle or Maven with auto-import, you should exclude module files, 293 | # since they will be recreated, and may cause churn. Uncomment if using 294 | # auto-import. 295 | # .idea/modules.xml 296 | # .idea/*.iml 297 | # .idea/modules 298 | 299 | # CMake 300 | 301 | # Mongo Explorer plugin 302 | 303 | # File-based project format 304 | 305 | # IntelliJ 306 | 307 | # mpeltonen/sbt-idea plugin 308 | 309 | # JIRA plugin 310 | 311 | # Cursive Clojure plugin 312 | 313 | # Crashlytics plugin (for Android Studio and IntelliJ) 314 | 315 | # Editor-based Rest Client 316 | 317 | # Android studio 3.1+ serialized cache file 318 | 319 | # JetBrains templates 320 | 321 | ### WebStorm Patch ### 322 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 323 | 324 | # *.iml 325 | # modules.xml 326 | # .idea/misc.xml 327 | # *.ipr 328 | 329 | # Sonarlint plugin 330 | 331 | ### Windows ### 332 | # Windows thumbnail cache files 333 | Thumbs.db 334 | ehthumbs.db 335 | ehthumbs_vista.db 336 | 337 | # Dump file 338 | *.stackdump 339 | 340 | # Folder config file 341 | [Dd]esktop.ini 342 | 343 | # Recycle Bin used on file shares 344 | $RECYCLE.BIN/ 345 | 346 | # Windows Installer files 347 | *.cab 348 | *.msi 349 | *.msix 350 | *.msm 351 | *.msp 352 | 353 | # Windows shortcuts 354 | *.lnk 355 | 356 | ### VisualStudio ### 357 | ## Ignore Visual Studio temporary files, build results, and 358 | ## files generated by popular Visual Studio add-ons. 359 | ## 360 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 361 | 362 | # User-specific files 363 | *.rsuser 364 | *.suo 365 | *.user 366 | *.userosscache 367 | *.sln.docstates 368 | 369 | # User-specific files (MonoDevelop/Xamarin Studio) 370 | *.userprefs 371 | 372 | # Mono auto generated files 373 | mono_crash.* 374 | 375 | # Build results 376 | [Dd]ebug/ 377 | [Dd]ebugPublic/ 378 | [Rr]elease/ 379 | [Rr]eleases/ 380 | x64/ 381 | x86/ 382 | [Aa][Rr][Mm]/ 383 | [Aa][Rr][Mm]64/ 384 | bld/ 385 | [Bb]in/ 386 | [Oo]bj/ 387 | [Ll]og/ 388 | 389 | # Visual Studio 2015/2017 cache/options directory 390 | .vs/ 391 | # Uncomment if you have tasks that create the project's static files in wwwroot 392 | #wwwroot/ 393 | 394 | # Visual Studio 2017 auto generated files 395 | Generated\ Files/ 396 | 397 | # MSTest test Results 398 | [Tt]est[Rr]esult*/ 399 | [Bb]uild[Ll]og.* 400 | 401 | # NUNIT 402 | *.VisualState.xml 403 | TestResult.xml 404 | 405 | # Build Results of an ATL Project 406 | [Dd]ebugPS/ 407 | [Rr]eleasePS/ 408 | dlldata.c 409 | 410 | # Benchmark Results 411 | BenchmarkDotNet.Artifacts/ 412 | 413 | # .NET Core 414 | project.lock.json 415 | project.fragment.lock.json 416 | artifacts/ 417 | 418 | # StyleCop 419 | StyleCopReport.xml 420 | 421 | # Files built by Visual Studio 422 | *_i.c 423 | *_p.c 424 | *_h.h 425 | *.ilk 426 | *.meta 427 | *.obj 428 | *.iobj 429 | *.pch 430 | *.pdb 431 | *.ipdb 432 | *.pgc 433 | *.pgd 434 | *.rsp 435 | *.sbr 436 | *.tlb 437 | *.tli 438 | *.tlh 439 | *.tmp 440 | *.tmp_proj 441 | *_wpftmp.csproj 442 | *.vspscc 443 | *.vssscc 444 | .builds 445 | *.pidb 446 | *.svclog 447 | *.scc 448 | 449 | # Chutzpah Test files 450 | _Chutzpah* 451 | 452 | # Visual C++ cache files 453 | ipch/ 454 | *.aps 455 | *.ncb 456 | *.opendb 457 | *.opensdf 458 | *.sdf 459 | *.cachefile 460 | *.VC.db 461 | *.VC.VC.opendb 462 | 463 | # Visual Studio profiler 464 | *.psess 465 | *.vsp 466 | *.vspx 467 | *.sap 468 | 469 | # Visual Studio Trace Files 470 | *.e2e 471 | 472 | # TFS 2012 Local Workspace 473 | $tf/ 474 | 475 | # Guidance Automation Toolkit 476 | *.gpState 477 | 478 | # ReSharper is a .NET coding add-in 479 | _ReSharper*/ 480 | *.[Rr]e[Ss]harper 481 | *.DotSettings.user 482 | 483 | # JustCode is a .NET coding add-in 484 | .JustCode 485 | 486 | # TeamCity is a build add-in 487 | _TeamCity* 488 | 489 | # DotCover is a Code Coverage Tool 490 | *.dotCover 491 | 492 | # AxoCover is a Code Coverage Tool 493 | .axoCover/* 494 | !.axoCover/settings.json 495 | 496 | # Visual Studio code coverage results 497 | *.coverage 498 | *.coveragexml 499 | 500 | # NCrunch 501 | _NCrunch_* 502 | .*crunch*.local.xml 503 | nCrunchTemp_* 504 | 505 | # MightyMoose 506 | *.mm.* 507 | AutoTest.Net/ 508 | 509 | # Web workbench (sass) 510 | .sass-cache/ 511 | 512 | # Installshield output folder 513 | [Ee]xpress/ 514 | 515 | # DocProject is a documentation generator add-in 516 | DocProject/buildhelp/ 517 | DocProject/Help/*.HxT 518 | DocProject/Help/*.HxC 519 | DocProject/Help/*.hhc 520 | DocProject/Help/*.hhk 521 | DocProject/Help/*.hhp 522 | DocProject/Help/Html2 523 | DocProject/Help/html 524 | 525 | # Click-Once directory 526 | publish/ 527 | 528 | # Publish Web Output 529 | *.[Pp]ublish.xml 530 | *.azurePubxml 531 | # Note: Comment the next line if you want to checkin your web deploy settings, 532 | # but database connection strings (with potential passwords) will be unencrypted 533 | *.pubxml 534 | *.publishproj 535 | 536 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 537 | # checkin your Azure Web App publish settings, but sensitive information contained 538 | # in these scripts will be unencrypted 539 | PublishScripts/ 540 | 541 | # NuGet Packages 542 | *.nupkg 543 | # The packages folder can be ignored because of Package Restore 544 | **/[Pp]ackages/* 545 | # except build/, which is used as an MSBuild target. 546 | !**/[Pp]ackages/build/ 547 | # Uncomment if necessary however generally it will be regenerated when needed 548 | #!**/[Pp]ackages/repositories.config 549 | # NuGet v3's project.json files produces more ignorable files 550 | *.nuget.props 551 | *.nuget.targets 552 | 553 | # Microsoft Azure Build Output 554 | csx/ 555 | *.build.csdef 556 | 557 | # Microsoft Azure Emulator 558 | ecf/ 559 | rcf/ 560 | 561 | # Windows Store app package directories and files 562 | AppPackages/ 563 | BundleArtifacts/ 564 | Package.StoreAssociation.xml 565 | _pkginfo.txt 566 | *.appx 567 | *.appxbundle 568 | *.appxupload 569 | 570 | # Visual Studio cache files 571 | # files ending in .cache can be ignored 572 | *.[Cc]ache 573 | # but keep track of directories ending in .cache 574 | !?*.[Cc]ache/ 575 | 576 | # Others 577 | ClientBin/ 578 | ~$* 579 | *.dbmdl 580 | *.dbproj.schemaview 581 | *.jfm 582 | *.pfx 583 | *.publishsettings 584 | orleans.codegen.cs 585 | 586 | # Including strong name files can present a security risk 587 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 588 | #*.snk 589 | 590 | # Since there are multiple workflows, uncomment next line to ignore bower_components 591 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 592 | #bower_components/ 593 | 594 | # RIA/Silverlight projects 595 | Generated_Code/ 596 | 597 | # Backup & report files from converting an old project file 598 | # to a newer Visual Studio version. Backup files are not needed, 599 | # because we have git ;-) 600 | _UpgradeReport_Files/ 601 | Backup*/ 602 | UpgradeLog*.XML 603 | UpgradeLog*.htm 604 | ServiceFabricBackup/ 605 | *.rptproj.bak 606 | 607 | # SQL Server files 608 | *.mdf 609 | *.ldf 610 | *.ndf 611 | 612 | # Business Intelligence projects 613 | *.rdl.data 614 | *.bim.layout 615 | *.bim_*.settings 616 | *.rptproj.rsuser 617 | *- Backup*.rdl 618 | 619 | # Microsoft Fakes 620 | FakesAssemblies/ 621 | 622 | # GhostDoc plugin setting file 623 | *.GhostDoc.xml 624 | 625 | # Node.js Tools for Visual Studio 626 | .ntvs_analysis.dat 627 | 628 | # Visual Studio 6 build log 629 | *.plg 630 | 631 | # Visual Studio 6 workspace options file 632 | *.opt 633 | 634 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 635 | *.vbw 636 | 637 | # Visual Studio LightSwitch build output 638 | **/*.HTMLClient/GeneratedArtifacts 639 | **/*.DesktopClient/GeneratedArtifacts 640 | **/*.DesktopClient/ModelManifest.xml 641 | **/*.Server/GeneratedArtifacts 642 | **/*.Server/ModelManifest.xml 643 | _Pvt_Extensions 644 | 645 | # Paket dependency manager 646 | .paket/paket.exe 647 | paket-files/ 648 | 649 | # FAKE - F# Make 650 | .fake/ 651 | 652 | # CodeRush personal settings 653 | .cr/personal 654 | 655 | # Python Tools for Visual Studio (PTVS) 656 | __pycache__/ 657 | *.pyc 658 | 659 | # Cake - Uncomment if you are using it 660 | # tools/** 661 | # !tools/packages.config 662 | 663 | # Tabs Studio 664 | *.tss 665 | 666 | # Telerik's JustMock configuration file 667 | *.jmconfig 668 | 669 | # BizTalk build output 670 | *.btp.cs 671 | *.btm.cs 672 | *.odx.cs 673 | *.xsd.cs 674 | 675 | # OpenCover UI analysis results 676 | OpenCover/ 677 | 678 | # Azure Stream Analytics local run output 679 | ASALocalRun/ 680 | 681 | # MSBuild Binary and Structured Log 682 | *.binlog 683 | 684 | # NVidia Nsight GPU debugger configuration file 685 | *.nvuser 686 | 687 | # MFractors (Xamarin productivity tool) working folder 688 | .mfractor/ 689 | 690 | # Local History for Visual Studio 691 | .localhistory/ 692 | 693 | # BeatPulse healthcheck temp database 694 | healthchecksdb 695 | 696 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 697 | MigrationBackup/ 698 | 699 | # End of https://www.gitignore.io/api/node,linux,macos,windows,intellij,webstorm,jetbrains,visualstudio,visualstudiocode 700 | 701 | .idea/ 702 | 703 | build -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "auth0-react-sample", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@auth0/auth0-react": "^1.1.0", 7 | "@fortawesome/fontawesome-svg-core": "^1.2.30", 8 | "@fortawesome/free-solid-svg-icons": "^5.14.0", 9 | "@fortawesome/react-fontawesome": "^0.1.11", 10 | "@testing-library/jest-dom": "^4.2.4", 11 | "@testing-library/react": "^9.3.2", 12 | "@testing-library/user-event": "^7.1.2", 13 | "react": "^16.13.1", 14 | "react-dom": "^16.13.1", 15 | "react-router-dom": "^5.2.0", 16 | "react-scripts": "^3.4.3" 17 | }, 18 | "scripts": { 19 | "start": "cross-env PORT=4040 react-scripts start", 20 | "build": "react-scripts build", 21 | "test": "react-scripts test", 22 | "eject": "react-scripts eject" 23 | }, 24 | "eslintConfig": { 25 | "extends": "react-app" 26 | }, 27 | "browserslist": { 28 | "production": [ 29 | ">0.2%", 30 | "not dead", 31 | "not op_mini all" 32 | ], 33 | "development": [ 34 | "last 1 chrome version", 35 | "last 1 firefox version", 36 | "last 1 safari version" 37 | ] 38 | }, 39 | "devDependencies": { 40 | "cross-env": "^7.0.2", 41 | "prettier": "^2.0.5" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /frontend/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 16 | 22 | 26 | Auth0 React Sample 27 | 28 | 29 | 30 |
31 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /frontend/src/app.css: -------------------------------------------------------------------------------- 1 | .next-steps .fa-link { 2 | margin-right: 5px; 3 | } 4 | 5 | /* Fix for use only flexbox in content area */ 6 | .next-steps .row { 7 | margin-bottom: 0; 8 | } 9 | 10 | .next-steps .col-md-5 { 11 | margin-bottom: 3rem; 12 | } 13 | 14 | @media (max-width: 768px) { 15 | .next-steps .col-md-5 { 16 | margin-bottom: 0; 17 | } 18 | } 19 | 20 | .spinner { 21 | position: absolute; 22 | display: flex; 23 | justify-content: center; 24 | height: 100vh; 25 | width: 100vw; 26 | background-color: white; 27 | top: 0; 28 | bottom: 0; 29 | left: 0; 30 | right: 0; 31 | } 32 | 33 | .result-block-container .result-block { 34 | opacity: 1; 35 | } 36 | -------------------------------------------------------------------------------- /frontend/src/app.js: -------------------------------------------------------------------------------- 1 | // src/app.js 2 | 3 | import React from "react"; 4 | import { Route, Switch } from "react-router-dom"; 5 | import { useAuth0 } from "@auth0/auth0-react"; 6 | 7 | import { NavBar, Footer, Loading } from "./components"; 8 | import { Home, Profile, ExternalApi } from "./views"; 9 | import ProtectedRoute from "./auth/protected-route"; 10 | 11 | import "./app.css"; 12 | 13 | const App = () => { 14 | const { isLoading } = useAuth0(); 15 | 16 | if (isLoading) { 17 | return ; 18 | } 19 | 20 | return ( 21 |
22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 |
30 |
31 |
32 | ); 33 | }; 34 | 35 | export default App; 36 | -------------------------------------------------------------------------------- /frontend/src/auth/auth0-provider-with-history.js: -------------------------------------------------------------------------------- 1 | // src/auth/auth0-provider-with-history.js 2 | 3 | import React from "react"; 4 | import { useHistory } from "react-router-dom"; 5 | import { Auth0Provider } from "@auth0/auth0-react"; 6 | 7 | const Auth0ProviderWithHistory = ({ children }) => { 8 | const history = useHistory(); 9 | const domain = process.env.REACT_APP_AUTH0_DOMAIN; 10 | const clientId = process.env.REACT_APP_AUTH0_CLIENT_ID; 11 | const audience = process.env.REACT_APP_AUTH0_AUDIENCE; 12 | 13 | const onRedirectCallback = (appState) => { 14 | history.push(appState?.returnTo || window.location.pathname); 15 | }; 16 | 17 | return ( 18 | 25 | {children} 26 | 27 | ); 28 | }; 29 | 30 | export default Auth0ProviderWithHistory; 31 | -------------------------------------------------------------------------------- /frontend/src/auth/protected-route.js: -------------------------------------------------------------------------------- 1 | // src/auth/protected-route.js 2 | 3 | import React from "react"; 4 | import { Route } from "react-router-dom"; 5 | import { withAuthenticationRequired } from "@auth0/auth0-react"; 6 | import { Loading } from "../components/index"; 7 | 8 | const ProtectedRoute = ({ component, ...args }) => ( 9 | , 12 | })} 13 | {...args} 14 | /> 15 | ); 16 | 17 | export default ProtectedRoute; 18 | -------------------------------------------------------------------------------- /frontend/src/components/auth-nav.js: -------------------------------------------------------------------------------- 1 | // src/components/auth-nav.js 2 | 3 | import React from "react"; 4 | import AuthenticationButton from "./authentication-button"; 5 | 6 | const AuthNav = () => ( 7 |
8 | 9 |
10 | ); 11 | 12 | export default AuthNav; 13 | -------------------------------------------------------------------------------- /frontend/src/components/authentication-button.js: -------------------------------------------------------------------------------- 1 | // src/components/authentication-button.js 2 | 3 | import React from "react"; 4 | 5 | import LoginButton from "./login-button"; 6 | import LogoutButton from "./logout-button"; 7 | 8 | import { useAuth0 } from "@auth0/auth0-react"; 9 | 10 | const AuthenticationButton = () => { 11 | const { isAuthenticated } = useAuth0(); 12 | 13 | return isAuthenticated ? : ; 14 | }; 15 | 16 | export default AuthenticationButton; 17 | -------------------------------------------------------------------------------- /frontend/src/components/footer.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Footer = () => ( 4 | 13 | ); 14 | 15 | export default Footer; 16 | -------------------------------------------------------------------------------- /frontend/src/components/hero.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const logo = "https://cdn.auth0.com/blog/auth0-react-sample/assets/logo.png"; 4 | 5 | const Hero = () => ( 6 |
7 | React logo 8 |

React Sample Project

9 |

10 | This is a sample application that demonstrates an authentication flow for 11 | an SPA, using{" "} 12 | 17 | React 18 | 19 |

20 |
21 | ); 22 | 23 | export default Hero; 24 | -------------------------------------------------------------------------------- /frontend/src/components/home-content.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; 3 | import { faLink } from "@fortawesome/free-solid-svg-icons"; 4 | 5 | const HomeContent = () => ( 6 |
7 |

What can I do next?

8 | 9 |
10 |
11 |
12 | 17 | 18 | Configure other identity providers 19 | 20 |
21 |

22 | Auth0 supports social providers as Facebook, Twitter, Instagram and 23 | 100+, Enterprise providers as Microsoft Office 365, Google Apps, 24 | Azure, and more. You can also use any OAuth2 Authorization Server. 25 |

26 |
27 | 28 |
29 | 30 |
31 |
32 | 37 | 38 | Enable Multi-Factor Authentication 39 | 40 |
41 |

42 | Add an extra layer of security by enabling Multi-factor 43 | Authentication, requiring your users to provide more than one piece of 44 | identifying information. Push notifications, authenticator apps, SMS, 45 | and DUO Security are supported. 46 |

47 |
48 |
49 | 50 |
51 |
52 |
53 | 58 | 59 | Anomaly Detection 60 | 61 |
62 |

63 | Auth0 can detect anomalies and stop malicious attempts to access your 64 | application. Anomaly detection can alert you and your users of 65 | suspicious activity, as well as block further login attempts. 66 |

67 |
68 | 69 |
70 | 71 |
72 |
73 | 78 | 79 | Learn About Rules 80 | 81 |
82 |

83 | Rules are JavaScript functions that execute when a user authenticates 84 | to your application. They run once the authentication process is 85 | complete, and you can use them to customize and extend Auth0's 86 | capabilities. 87 |

88 |
89 |
90 |
91 | ); 92 | 93 | export default HomeContent; 94 | -------------------------------------------------------------------------------- /frontend/src/components/index.js: -------------------------------------------------------------------------------- 1 | import HomeContent from "./home-content"; 2 | import Footer from "./footer"; 3 | import Hero from "./hero"; 4 | import Loading from "./loading"; 5 | import NavBar from "./nav-bar"; 6 | 7 | export { HomeContent, Footer, Hero, Loading, NavBar }; 8 | -------------------------------------------------------------------------------- /frontend/src/components/loading.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const loadingImg = 3 | "https://cdn.auth0.com/blog/auth0-react-sample/assets/loading.svg"; 4 | 5 | const Loading = () => ( 6 |
7 | Loading... 8 |
9 | ); 10 | 11 | export default Loading; 12 | -------------------------------------------------------------------------------- /frontend/src/components/login-button.js: -------------------------------------------------------------------------------- 1 | // src/components/login-button.js 2 | 3 | import React from "react"; 4 | import { useAuth0 } from "@auth0/auth0-react"; 5 | 6 | const LoginButton = () => { 7 | const { loginWithRedirect } = useAuth0(); 8 | return ( 9 | 15 | ); 16 | }; 17 | 18 | export default LoginButton; 19 | -------------------------------------------------------------------------------- /frontend/src/components/logout-button.js: -------------------------------------------------------------------------------- 1 | // src/components/logout-button.js 2 | 3 | import React from "react"; 4 | import { useAuth0 } from "@auth0/auth0-react"; 5 | 6 | const LogoutButton = () => { 7 | const { logout } = useAuth0(); 8 | return ( 9 | 19 | ); 20 | }; 21 | 22 | export default LogoutButton; 23 | -------------------------------------------------------------------------------- /frontend/src/components/main-nav.js: -------------------------------------------------------------------------------- 1 | import {NavLink} from "react-router-dom"; 2 | import React from "react"; 3 | 4 | const MainNav = () => ( 5 |
6 | 12 | Home 13 | 14 | 20 | Profile 21 | 22 | 28 | External API 29 | 30 |
31 | ); 32 | 33 | export default MainNav; 34 | -------------------------------------------------------------------------------- /frontend/src/components/nav-bar.js: -------------------------------------------------------------------------------- 1 | // src/components/nav-bar.js 2 | 3 | import React from "react"; 4 | 5 | import MainNav from "./main-nav"; 6 | import AuthNav from "./auth-nav"; 7 | 8 | const NavBar = () => { 9 | return ( 10 |
11 | 18 |
19 | ); 20 | }; 21 | 22 | export default NavBar; 23 | -------------------------------------------------------------------------------- /frontend/src/components/signup-button.js: -------------------------------------------------------------------------------- 1 | // src/components/signup-button.js 2 | 3 | import React from "react"; 4 | import { useAuth0 } from "@auth0/auth0-react"; 5 | 6 | const SignupButton = () => { 7 | const { loginWithRedirect } = useAuth0(); 8 | return ( 9 | 19 | ); 20 | }; 21 | 22 | export default SignupButton; 23 | -------------------------------------------------------------------------------- /frontend/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 6 | sans-serif; 7 | -webkit-font-smoothing: antialiased; 8 | -moz-osx-font-smoothing: grayscale; 9 | overflow-y: scroll; 10 | } 11 | 12 | code { 13 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 14 | monospace; 15 | } 16 | 17 | .next-steps .fa-link { 18 | margin-right: 5px; 19 | } 20 | 21 | /* Fix for use only flexbox in content area */ 22 | .next-steps .row { 23 | margin-bottom: 0; 24 | } 25 | 26 | .next-steps .col-md-5 { 27 | margin-bottom: 3rem; 28 | } 29 | 30 | @media (max-width: 768px) { 31 | .next-steps .col-md-5 { 32 | margin-bottom: 0; 33 | } 34 | } 35 | 36 | .spinner { 37 | position: absolute; 38 | display: flex; 39 | justify-content: center; 40 | height: 100vh; 41 | width: 100vw; 42 | background-color: white; 43 | top: 0; 44 | bottom: 0; 45 | left: 0; 46 | right: 0; 47 | } 48 | 49 | .result-block-container .result-block { 50 | opacity: 1; 51 | } 52 | 53 | .loading { 54 | display: flex; 55 | min-height: 500px; 56 | align-items: center; 57 | justify-content: center; 58 | } 59 | 60 | .userImg { 61 | border-radius: 100px; 62 | display: block; 63 | height: 100px; 64 | margin: 0 auto; 65 | width: 100px; 66 | } 67 | 68 | .hero .app-logo { 69 | max-width: 10.5rem; 70 | } 71 | -------------------------------------------------------------------------------- /frontend/src/index.js: -------------------------------------------------------------------------------- 1 | // src/index.js 2 | 3 | import React from "react"; 4 | import ReactDOM from "react-dom"; 5 | import App from "./app"; 6 | import { BrowserRouter as Router } from "react-router-dom"; 7 | import Auth0ProviderWithHistory from "./auth/auth0-provider-with-history"; 8 | 9 | import "./index.css"; 10 | 11 | ReactDOM.render( 12 | 13 | 14 | 15 | 16 | , 17 | document.getElementById("root") 18 | ); 19 | -------------------------------------------------------------------------------- /frontend/src/views/external-api.js: -------------------------------------------------------------------------------- 1 | // src/views/external-api.js 2 | 3 | import React, { useState } from "react"; 4 | import { useAuth0 } from "@auth0/auth0-react"; 5 | 6 | const ExternalApi = () => { 7 | const [message, setMessage] = useState(""); 8 | const serverUrl = process.env.REACT_APP_SERVER_URL; 9 | 10 | const { getAccessTokenSilently } = useAuth0(); 11 | 12 | const callApi = async () => { 13 | try { 14 | const response = await fetch(`${serverUrl}/api/messages/public-message`); 15 | 16 | const responseData = await response.json(); 17 | 18 | setMessage(responseData.message); 19 | } catch (error) { 20 | setMessage(error.message); 21 | } 22 | }; 23 | 24 | const callSecureApi = async () => { 25 | try { 26 | const token = await getAccessTokenSilently(); 27 | 28 | const response = await fetch( 29 | `${serverUrl}/api/messages/protected-message`, 30 | { 31 | headers: { 32 | Authorization: `Bearer ${token}`, 33 | }, 34 | } 35 | ); 36 | 37 | const responseData = await response.json(); 38 | 39 | setMessage(responseData.message); 40 | } catch (error) { 41 | setMessage(error.message); 42 | } 43 | }; 44 | 45 | return ( 46 |
47 |

External API

48 |

49 | Use these buttons to call an external API. The protected API call has an 50 | access token in its authorization header. The API server will validate 51 | the access token using the Auth0 Audience value. 52 |

53 |
58 | 61 | 68 |
69 | {message && ( 70 |
71 |
Result
72 |
73 |
74 | {message} 75 |
76 |
77 |
78 | )} 79 |
80 | ); 81 | }; 82 | 83 | export default ExternalApi; 84 | -------------------------------------------------------------------------------- /frontend/src/views/home.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from "react"; 2 | 3 | import { Hero, HomeContent } from "../components"; 4 | 5 | const Home = () => ( 6 | 7 | 8 |
9 | 10 |
11 | ); 12 | 13 | export default Home; 14 | -------------------------------------------------------------------------------- /frontend/src/views/index.js: -------------------------------------------------------------------------------- 1 | import ExternalApi from "./external-api"; 2 | import Home from "./home"; 3 | import Profile from "./profile"; 4 | 5 | export { ExternalApi, Home, Profile }; 6 | -------------------------------------------------------------------------------- /frontend/src/views/profile.js: -------------------------------------------------------------------------------- 1 | // src/views/profile.js 2 | 3 | import React from "react"; 4 | 5 | import { useAuth0 } from "@auth0/auth0-react"; 6 | 7 | const Profile = () => { 8 | const { user } = useAuth0(); 9 | const { name, picture, email } = user; 10 | 11 | return ( 12 |
13 |
14 |
15 | Profile 20 |
21 |
22 |

{name}

23 |

{email}

24 |
25 |
26 |
27 |
28 |           {JSON.stringify(user, null, 2)}
29 |         
30 |
31 |
32 | ); 33 | }; 34 | 35 | export default Profile; 36 | -------------------------------------------------------------------------------- /images/auth0-react.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesqquick/auth0-react-workshop/5fd13198c579a9122c2dd94ba5e9746555414198/images/auth0-react.jpg --------------------------------------------------------------------------------