From cc44c409d7678cd05db173c113a9bedee14d3fcb Mon Sep 17 00:00:00 2001 From: Ben Ramey Date: Mon, 4 Oct 2021 09:59:29 -0500 Subject: [PATCH] Get config variables in auth0 in env file --- api/app.js | 42 ++++++++------------------ api/config/passport.js | 31 ------------------- api/middleware/secure.js | 19 ++++++++++++ api/package.json | 6 ++-- site/package.json | 5 +-- site/snowpack.config.mjs | 3 ++ site/src/components/AuthTest.jsx | 7 +++-- site/src/components/ProfileFromApi.jsx | 10 ++---- site/src/config.js | 10 +++++- site/src/pages/index.astro | 1 + 10 files changed, 58 insertions(+), 76 deletions(-) delete mode 100644 api/config/passport.js create mode 100644 api/middleware/secure.js create mode 100644 site/snowpack.config.mjs diff --git a/api/app.js b/api/app.js index a751825..d38cb2a 100644 --- a/api/app.js +++ b/api/app.js @@ -1,17 +1,10 @@ const express = require("express"); -const app = express(); -const passport = require("passport"); +const jwtAuthz = require("express-jwt-authz"); +const asyncHandler = require("express-async-handler"); const { users } = require("./controllers"); +const secure = require("./middleware/secure"); -/** - * Configure Passport - */ - -try { - require("./config/passport")(passport); -} catch (error) { - console.log(error); -} +const app = express(); /** * Configure Express.js Middleware @@ -25,19 +18,9 @@ app.use(function (req, res, next) { next(); }); -// Initialize Passport and restore authentication state, if any, from the session -app.use(passport.initialize()); -app.use(passport.session()); - // Enable JSON use app.use(express.json()); -// Since Express doesn't support error handling of promises out of the box, -// this handler enables that -const asyncHandler = (fn) => (req, res, next) => { - return Promise.resolve(fn(req, res, next)).catch(next); -}; - /** * Routes - Public */ @@ -46,10 +29,6 @@ app.options(`*`, (req, res) => { res.status(200).send(); }); -app.post(`/users/register`, asyncHandler(users.register)); - -app.post(`/users/login`, asyncHandler(users.login)); - app.get(`/test/`, (req, res) => { res.status(200).send("Request received"); }); @@ -58,10 +37,13 @@ app.get(`/test/`, (req, res) => { * Routes - Protected */ -app.post( - `/user`, - passport.authenticate("jwt", { session: false }), - asyncHandler(users.get) +app.get( + "/test-authorized/", + secure, + jwtAuthz(["read:stuff"]), + function (req, res) { + res.send("Secured Resource"); + } ); /** @@ -69,7 +51,7 @@ app.post( */ app.get(`/*`, (req, res) => { - res.status(404).send("Route not found"); + res.status(404).json({ error: "Not Found" }); }); /** diff --git a/api/config/passport.js b/api/config/passport.js deleted file mode 100644 index 3c7adfe..0000000 --- a/api/config/passport.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Config: Passport.js - */ - -const StrategyJWT = require("passport-jwt").Strategy; -const ExtractJWT = require("passport-jwt").ExtractJwt; - -const { users } = require("../models"); - -module.exports = (passport) => { - const options = {}; - options.jwtFromRequest = ExtractJWT.fromAuthHeaderAsBearerToken(); - options.secretOrKey = process.env.tokenSecret; // Change this to only use your own secret token - - passport.use( - new StrategyJWT(options, async (jwtPayload, done) => { - let user; - try { - user = await users.getById(jwtPayload.id); - } catch (error) { - console.log(error); - return done(error, null); - } - - if (!user) { - return done(null, false); - } - return done(null, user); - }) - ); -}; diff --git a/api/middleware/secure.js b/api/middleware/secure.js new file mode 100644 index 0000000..e5e4834 --- /dev/null +++ b/api/middleware/secure.js @@ -0,0 +1,19 @@ +const jwt = require("express-jwt"); +const jwksRsa = require("jwks-rsa"); + +const secure = jwt({ + // Dynamically provide a signing key based on the kid in the header and the signing keys provided by the JWKS endpoint + secret: jwksRsa.expressJwtSecret({ + cache: true, + rateLimit: true, + jwksRequestsPerMinute: 5, + jwksUri: `https://${process.env.SNOWPACK_PUBLIC_AUTH0_DOMAIN}/.well-known/jwks.json`, + }), + + // Validate the audience and the issuer + audience: `https://${process.env.SNOWPACK_PUBLIC_API_DOMAIN}/`, //replace with your API's audience, available at Dashboard > APIs + issuer: `https://${process.env.SNOWPACK_PUBLIC_AUTH0_DOMAIN}/`, + algorithms: ["RS256"], +}); + +module.exports = secure; diff --git a/api/package.json b/api/package.json index 2574195..2107470 100644 --- a/api/package.json +++ b/api/package.json @@ -5,9 +5,11 @@ "dependencies": { "bcryptjs": "^2.4.3", "express": "^4.17.1", + "express-async-handler": "^1.1.4", + "express-jwt": "^6.1.0", + "express-jwt-authz": "^2.4.1", "jsonwebtoken": "^8.5.1", - "passport": "^0.4.1", - "passport-jwt": "^4.0.0", + "jwks-rsa": "^2.0.4", "shortid": "^2.2.15" }, "devDependencies": {}, diff --git a/site/package.json b/site/package.json index 77f6f82..a31100e 100644 --- a/site/package.json +++ b/site/package.json @@ -9,8 +9,9 @@ "preview": "astro preview" }, "devDependencies": { - "astro": "^0.20.7", - "@astrojs/renderer-react": "^0.2.1" + "@astrojs/renderer-react": "^0.2.1", + "@snowpack/plugin-dotenv": "^2.2.0", + "astro": "^0.20.7" }, "dependencies": { "@auth0/auth0-react": "^1.8.0" diff --git a/site/snowpack.config.mjs b/site/snowpack.config.mjs new file mode 100644 index 0000000..7a75359 --- /dev/null +++ b/site/snowpack.config.mjs @@ -0,0 +1,3 @@ +export default { + plugins: [["@snowpack/plugin-dotenv", { dir: "../" }]], +}; diff --git a/site/src/components/AuthTest.jsx b/site/src/components/AuthTest.jsx index 02fad2a..c0f30b8 100644 --- a/site/src/components/AuthTest.jsx +++ b/site/src/components/AuthTest.jsx @@ -4,14 +4,15 @@ import LoginButton from "./LoginButton"; import LogoutButton from "./LogoutButton"; import Profile from "./Profile"; import ProfileFromApi from "./ProfileFromApi"; +import config from "../config"; const AuthTest = () => { return ( diff --git a/site/src/components/ProfileFromApi.jsx b/site/src/components/ProfileFromApi.jsx index c11feda..ffc0392 100644 --- a/site/src/components/ProfileFromApi.jsx +++ b/site/src/components/ProfileFromApi.jsx @@ -7,14 +7,14 @@ const ProfileFromApi = () => { useEffect(() => { const getMessage = async () => { - try { const accessToken = await getAccessTokenSilently({ audience: "https://1t8da6s66e.execute-api.us-east-1.amazonaws.com/", scope: "read:stuff", }); - const authorizedUrl = "https://1t8da6s66e.execute-api.us-east-1.amazonaws.com/authorized"; + const authorizedUrl = + "https://1t8da6s66e.execute-api.us-east-1.amazonaws.com/authorized"; const authorizedResponse = await fetch(authorizedUrl, { headers: { @@ -40,11 +40,7 @@ const ProfileFromApi = () => {

{user.name}

{user.email}

API Message

- {message ? ( -
{message}
- ) : ( - "No message found" - )} + {message ?
{message}
: "No message found"} ) ); diff --git a/site/src/config.js b/site/src/config.js index 98b75f0..25756fc 100644 --- a/site/src/config.js +++ b/site/src/config.js @@ -13,6 +13,14 @@ config.domains = {}; * This will enable your front-end to communicate with your back-end. * (e.g. 'https://api.mydomain.com' or 'https://091jafsl10.execute-api.us-east-1.amazonaws.com') */ -config.domains.api = "https://1t8da6s66e.execute-api.us-east-1.amazonaws.com"; +config.domains.api = `https://${import.meta.env.SNOWPACK_PUBLIC_API_DOMAIN}`; + +/** + * Auth0 config values + */ +config.auth0 = {}; +config.auth0.domain = import.meta.env.SNOWPACK_PUBLIC_AUTH0_DOMAIN; +config.auth0.clientId = import.meta.env.SNOWPACK_PUBLIC_AUTH0_CLIENT_ID; +config.auth0.audience = `https://${import.meta.env.SNOWPACK_PUBLIC_API_DOMAIN}/`; export default config; diff --git a/site/src/pages/index.astro b/site/src/pages/index.astro index a8c439b..5cdcf6c 100644 --- a/site/src/pages/index.astro +++ b/site/src/pages/index.astro @@ -14,6 +14,7 @@ let title = 'My Astro Site'; // Full Astro Component Syntax: // https://docs.astro.build/core-concepts/astro-components/ + ---