From e14485228f139730e320860ae7960042963eac1b Mon Sep 17 00:00:00 2001 From: bhargavjulaganti Date: Sun, 24 Mar 2024 18:25:37 -0400 Subject: [PATCH] adding auth0 --- README.md | 3 ++ api-server/.env | 2 + api-server/app.js | 14 +++++- api-server/package-lock.json | 47 +++++++++++++++++++ api-server/package.json | 4 +- candy-api-tests/playwright.config.ts | 12 +++++ .../tests/api-candy-auth0-tests.spec.ts | 28 +++++++++++ 7 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 api-server/.env create mode 100644 candy-api-tests/tests/api-candy-auth0-tests.spec.ts diff --git a/README.md b/README.md index d598f83..f056320 100644 --- a/README.md +++ b/README.md @@ -143,3 +143,6 @@ Create a PUT request for the API endpoint `/api/candy` , with below requestBody + + + diff --git a/api-server/.env b/api-server/.env new file mode 100644 index 0000000..a6e8db1 --- /dev/null +++ b/api-server/.env @@ -0,0 +1,2 @@ +AUDIENCE=http://localhost:3010 +ISSUER_BASE_URL=https://dev-zzqedh33f717ukmd.us.auth0.com diff --git a/api-server/app.js b/api-server/app.js index 67692b6..24b44f2 100644 --- a/api-server/app.js +++ b/api-server/app.js @@ -1,9 +1,17 @@ const express = require('express'); const app = express(); +const { auth, requiredScopes } = require('express-oauth2-jwt-bearer'); +require('dotenv').config(); const port = 3000; // You can change the port as needed app.use(express.json()); +if (!process.env.ISSUER_BASE_URL || !process.env.AUDIENCE) { + throw 'Make sure you have ISSUER_BASE_URL, and AUDIENCE in your .env file'; +} + +const checkJwt = auth(); + // Sample candy data const candyData = [ { @@ -84,7 +92,11 @@ app.put('/api/candy/', (req, res) => { res.json(candyData[candyIndex]); }); - +app.get('/api/private/candy', checkJwt, function(req, res) { + res.json({ + message: 'Hello from a private endpoint! You need to be authenticated to hit the candy store' + }); +}); app.listen(port, () => { diff --git a/api-server/package-lock.json b/api-server/package-lock.json index c381c98..3b6f960 100644 --- a/api-server/package-lock.json +++ b/api-server/package-lock.json @@ -11,7 +11,9 @@ "dependencies": { "body-parser": "^1.20.2", "cors": "^2.8.5", + "dotenv": "^10.0.0", "express": "^4.18.2", + "express-oauth2-jwt-bearer": "^1.6.0", "jsonwebtoken": "^9.0.2" } }, @@ -163,6 +165,14 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", + "engines": { + "node": ">=10" + } + }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", @@ -238,6 +248,17 @@ "node": ">= 0.10.0" } }, + "node_modules/express-oauth2-jwt-bearer": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/express-oauth2-jwt-bearer/-/express-oauth2-jwt-bearer-1.6.0.tgz", + "integrity": "sha512-HXnez7vocYlOqlfF3ozPcf/WE3zxT7zfUNfeg5FHJnvNwhBYlNXiPOvuCtBalis8xcigvwtInzEKhBuH87+9ug==", + "dependencies": { + "jose": "^4.13.1" + }, + "engines": { + "node": "^12.19.0 || ^14.15.0 || ^16.13.0 || ^18.12.0 || ^20.2.0" + } + }, "node_modules/express/node_modules/body-parser": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", @@ -424,6 +445,14 @@ "node": ">= 0.10" } }, + "node_modules/jose": { + "version": "4.15.5", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.5.tgz", + "integrity": "sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg==", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/jsonwebtoken": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", @@ -951,6 +980,11 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" }, + "dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==" + }, "ecdsa-sig-formatter": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", @@ -1049,6 +1083,14 @@ } } }, + "express-oauth2-jwt-bearer": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/express-oauth2-jwt-bearer/-/express-oauth2-jwt-bearer-1.6.0.tgz", + "integrity": "sha512-HXnez7vocYlOqlfF3ozPcf/WE3zxT7zfUNfeg5FHJnvNwhBYlNXiPOvuCtBalis8xcigvwtInzEKhBuH87+9ug==", + "requires": { + "jose": "^4.13.1" + } + }, "finalhandler": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", @@ -1153,6 +1195,11 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" }, + "jose": { + "version": "4.15.5", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.5.tgz", + "integrity": "sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg==" + }, "jsonwebtoken": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", diff --git a/api-server/package.json b/api-server/package.json index 3eb2ad2..417e76f 100644 --- a/api-server/package.json +++ b/api-server/package.json @@ -12,6 +12,8 @@ "body-parser": "^1.20.2", "cors": "^2.8.5", "express": "^4.18.2", - "jsonwebtoken": "^9.0.2" + "jsonwebtoken": "^9.0.2", + "express-oauth2-jwt-bearer": "^1.6.0", + "dotenv": "^10.0.0" } } diff --git a/candy-api-tests/playwright.config.ts b/candy-api-tests/playwright.config.ts index 301801e..d74c569 100644 --- a/candy-api-tests/playwright.config.ts +++ b/candy-api-tests/playwright.config.ts @@ -1,5 +1,16 @@ import { defineConfig, devices } from '@playwright/test'; +// Define your secrets +export const config = { + // Other configurations... + secrets: { + client_id: 'XKDpzYJvVgsF7N6AgiGr0joOgEPQ06CR', + client_secret: 'bA4b3p8a72kiAS8SU4KJLZqEYEI2Kbo0PaHATS0VATLEV4aEITKhbeS16RUHVNw1', + // Add more secrets as needed + }, +}; + + /** * Read environment variables from file. * https://github.com/motdotla/dotenv @@ -30,6 +41,7 @@ export default defineConfig({ trace: 'on-first-retry', }, + /* Configure projects for major browsers */ projects: [ { diff --git a/candy-api-tests/tests/api-candy-auth0-tests.spec.ts b/candy-api-tests/tests/api-candy-auth0-tests.spec.ts new file mode 100644 index 0000000..ad26c30 --- /dev/null +++ b/candy-api-tests/tests/api-candy-auth0-tests.spec.ts @@ -0,0 +1,28 @@ +import { expect, test } from '@playwright/test' +import { config } from '../playwright.config'; + +test('get private endpoint', async ( {request})=> { + + const tokenResponse = await request.post('https://dev-zzqedh33f717ukmd.us.auth0.com/oauth/token', { + data: { + "client_id": config.secrets.client_id, + "client_secret": config.secrets.client_secret, + "audience": "http://localhost:3010", + "grant_type": "client_credentials" + } + }); + + expect(tokenResponse.status()).toBe(200); + + const tokenResponseAsJson = await tokenResponse.json(); + + + const response = await request.get('http://localhost:3000/api/private/candy', { + headers: { + 'Authorization': `Bearer ${tokenResponseAsJson.access_token}`, + } + }); + const responseAsJson = await response.json(); + + expect(response.status()).toBe(200); +})