From 2de3154bcc81c476fd9bd2f9cf56d83cb58878e8 Mon Sep 17 00:00:00 2001 From: Jenni Laakso Date: Wed, 25 Nov 2020 09:59:46 +0200 Subject: [PATCH 01/15] Add jose library --- package.json | 1 + yarn.lock | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/package.json b/package.json index b60dc1f301..a362c09473 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "full-icu": "^1.3.1", "helmet": "^4.0.0", "intl-pluralrules": "^1.0.3", + "jose": "3.1.0", "lodash": "^4.17.19", "mapbox-gl-multitouch": "^1.0.3", "moment": "^2.22.2", diff --git a/yarn.lock b/yarn.lock index d826caab6d..8cc502c712 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7634,6 +7634,11 @@ jest@26.6.0: import-local "^3.0.2" jest-cli "^26.6.0" +jose@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/jose/-/jose-3.1.0.tgz#31a48b76a2e0f5da4e9a1be261e430e0bfaa4a43" + integrity sha512-TLZFF0qAPlG0GZDrPw9HAiWKJcDuUbOp1WdjuS5cJ0reTzd1zS718zrUPOt7BIOViTA6PZpEnMt5cMQttJq3QA== + js-cookie@^2.1.3: version "2.2.1" resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8" From 3cb0c0abb38afbccbe4607fec2fee217de547b02 Mon Sep 17 00:00:00 2001 From: Jenni Laakso Date: Wed, 25 Nov 2020 10:10:02 +0200 Subject: [PATCH 02/15] Helper functions for proxy implementation --- server/api-util/idToken.js | 100 +++++++++++++++++++++++++++++++++++++ server/apiRouter.js | 18 +++++++ 2 files changed, 118 insertions(+) create mode 100644 server/api-util/idToken.js diff --git a/server/api-util/idToken.js b/server/api-util/idToken.js new file mode 100644 index 0000000000..9ee87664db --- /dev/null +++ b/server/api-util/idToken.js @@ -0,0 +1,100 @@ +const crypto = require('crypto'); +const { default: fromKeyLike } = require('jose/jwk/from_key_like'); +const { default: SignJWT } = require('jose/jwt/sign'); + +const radix = 10; +const PORT = parseInt(process.env.REACT_APP_DEV_API_SERVER_PORT, radix); +const rootUrl = process.env.REACT_APP_CANONICAL_ROOT_URL; +const useDevApiServer = process.env.NODE_ENV === 'development' && !!PORT; + +const issuerUrl = useDevApiServer ? `http://localhost:${PORT}/api` : `${rootUrl}/api`; + +/** + * Gets user information and creates the signed jwt for id token. + * + * @param {string} idpClientId the client id of the idp provider in Console + * @param {Object} options signing options containing signingAlg and required key information + * @param {Object} user user information containing at least firstName, lastName, email and emailVerified + * + * @return {Promise} idToken + */ +exports.createIdToken = (idpClientId, user, options) => { + if (!idpClientId) { + console.error('Missing idp client id!'); + return; + } + if (!user) { + console.error('Missing user information!'); + return; + } + + const signingAlg = options.signingAlg; + + // Currently Flex supports only RS256 signing algorithm. + if (signingAlg !== 'RS256') { + console.error(`${signingAlg} is not currently supported!`); + return; + } + + const { rsaPrivateKey, keyId } = options; + + if (!rsaPrivateKey) { + console.error('Missing RSA private key!'); + return; + } + + // We use jose library which requires the RSA key + // to be KeyLike format: + // https://github.com/panva/jose/blob/master/docs/types/_types_d_.keylike.md + const privateKey = crypto.createPrivateKey(rsaPrivateKey); + + const { userId, firstName, lastName, email, emailVerified } = user; + + const jwt = new SignJWT({ + given_name: firstName, + family_name: lastName, + email: email, + email_verified: emailVerified, + }) + .setProtectedHeader({ alg: signingAlg, kid: keyId }) + .setIssuedAt() + .setIssuer(issuerUrl) + .setSubject(userId) + .setAudience(idpClientId) + .setExpirationTime('1h') + .sign(privateKey); + + return jwt; +}; + +// Serves the discovery document in json format +// this document is expected to be found from +// api/.well-known/openid-configuration endpoint +exports.openIdConfiguration = (req, res) => { + res.json({ + issuer: issuerUrl, + jwks_uri: `${issuerUrl}/.well-known/jwks.json`, + subject_types_supported: ['public'], + id_token_signing_alg_values_supported: ['RS256'], + }); +}; + +/** + * @param {String} signingAlg signing algorithm, currently only RS256 is supported + * @param {Array} list containing keys to be served in json endpoint + * + * // Serves the RSA public key as JWK +// this document is expected to be found from +// api/.well-known/jwks.json endpoint as stated in discovery document + */ +exports.jwksUri = keys => (req, res) => { + const jwkKeys = keys.map(key => { + return fromKeyLike(crypto.createPublicKey(key.rsaPublicKey)).then(res => { + return { alg: key.alg, kid: key.keyId, ...res }; + }); + }); + + Promise.all(jwkKeys).then(resolvedJwkKeys => { + res.json({ keys: resolvedJwkKeys }); + }); +}; diff --git a/server/apiRouter.js b/server/apiRouter.js index c9a4b887eb..4618883639 100644 --- a/server/apiRouter.js +++ b/server/apiRouter.js @@ -21,6 +21,8 @@ const createUserWithIdp = require('./api/auth/createUserWithIdp'); const { authenticateFacebook, authenticateFacebookCallback } = require('./api/auth/facebook'); const { authenticateGoogle, authenticateGoogleCallback } = require('./api/auth/google'); +const { openIdConfiguration, jwksUri } = require('./api-util/idToken'); + const router = express.Router(); // ================ API router middleware: ================ // @@ -80,4 +82,20 @@ router.get('/auth/google', authenticateGoogle); // loginWithIdp endpoint in Flex API to authenticate user to Flex router.get('/auth/google/callback', authenticateGoogleCallback); +// These endpoints will be used if you FTW as OIDC proxy +// https://www.sharetribe.com/docs/cookbook-social-logins-and-sso/setup-open-id-connect-proxy/ +// All identity providers should provide an OpenID Connect discovery document: +// https://openid.net/specs/openid-connect-discovery-1_0.html +// And in the discovery document we need to define jwks_uri attribute +// which denotes the location of public signing keys + +const rsaSecretKey = process.env.RSA_SECRET_KEY; +const rsaPublicKey = process.env.RSA_PUBLIC_KEY; +const keyId = process.env.KEY_ID; + +if (rsaPublicKey && rsaSecretKey) { + router.get('/.well-known/openid-configuration', openIdConfiguration); + router.get('/.well-known/jwks.json', jwksUri([{ alg: 'RS256', rsaPublicKey, keyId }])); +} + module.exports = router; From 66b873eacfa4b0b0cadaa2c59151030184208614 Mon Sep 17 00:00:00 2001 From: Jenni Laakso Date: Fri, 4 Dec 2020 16:24:39 +0200 Subject: [PATCH 03/15] loginWithIdp: rename parameter clientID to idpClientId to make it less confusing --- server/api/auth/loginWithIdp.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/api/auth/loginWithIdp.js b/server/api/auth/loginWithIdp.js index b6a6c18871..1ad2086213 100644 --- a/server/api/auth/loginWithIdp.js +++ b/server/api/auth/loginWithIdp.js @@ -20,7 +20,7 @@ const httpsAgent = new https.Agent({ keepAlive: true }); const baseUrl = BASE_URL ? { baseUrl: BASE_URL } : {}; -module.exports = (err, user, req, res, clientID, idpId) => { +module.exports = (err, user, req, res, idpClientId, idpId) => { if (err) { log.error(err, 'fetching-user-data-from-idp-failed'); @@ -87,7 +87,7 @@ module.exports = (err, user, req, res, clientID, idpId) => { return sdk .loginWithIdp({ idpId, - idpClientId: clientID, + idpClientId, idpToken: user.idpToken, }) .then(response => { From 777ad3a897052595b9c8a4647bd238b6712da8d6 Mon Sep 17 00:00:00 2001 From: Jenni Laakso Date: Thu, 10 Dec 2020 11:10:23 +0200 Subject: [PATCH 04/15] Update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c919be46ff..ed6fc7b354 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,9 @@ way to update this template, but currently, we follow a pattern: ## Upcoming version 2020-XX-XX +- [add] Add helper functions for setting up your own OIDC authentication and using FTW server as + proxy when needed. [#1383](https://github.com/sharetribe/ftw-daily/pull/1383) + ## [v7.1.0] 2020-12-15 - [change] Handle entity update with sparse attributes. From 6a842ca25e3d443980390798824f19314dbb1267 Mon Sep 17 00:00:00 2001 From: Jenni Laakso Date: Wed, 16 Dec 2020 13:54:47 +0200 Subject: [PATCH 05/15] Update package.json and changelog --- CHANGELOG.md | 4 ++++ package.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed6fc7b354..e28f38aafe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,9 +14,13 @@ way to update this template, but currently, we follow a pattern: ## Upcoming version 2020-XX-XX +## [v7.2.0] 2020-12-16 + - [add] Add helper functions for setting up your own OIDC authentication and using FTW server as proxy when needed. [#1383](https://github.com/sharetribe/ftw-daily/pull/1383) + [v7.2.0]: https://github.com/sharetribe/ftw-daily/compare/v7.1.0...v7.2.0 + ## [v7.1.0] 2020-12-15 - [change] Handle entity update with sparse attributes. diff --git a/package.json b/package.json index a362c09473..3c82f4abc1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "app", - "version": "7.1.0", + "version": "7.2.0", "private": true, "license": "Apache-2.0", "dependencies": { From b054fb07c964afac3a1a5eebf6fb8339b95a7a09 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Dec 2020 21:38:30 +0000 Subject: [PATCH 06/15] Bump node-notifier from 8.0.0 to 8.0.1 Bumps [node-notifier](https://github.com/mikaelbr/node-notifier) from 8.0.0 to 8.0.1. - [Release notes](https://github.com/mikaelbr/node-notifier/releases) - [Changelog](https://github.com/mikaelbr/node-notifier/blob/v8.0.1/CHANGELOG.md) - [Commits](https://github.com/mikaelbr/node-notifier/compare/v8.0.0...v8.0.1) Signed-off-by: dependabot[bot] --- yarn.lock | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/yarn.lock b/yarn.lock index 8cc502c712..4e7e71da81 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8692,9 +8692,9 @@ node-modules-regexp@^1.0.0: integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= node-notifier@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-8.0.0.tgz#a7eee2d51da6d0f7ff5094bc7108c911240c1620" - integrity sha512-46z7DUmcjoYdaWyXouuFNNfUo6eFa94t23c53c+lG/9Cvauk4a98rAUp9672X5dxGdQmLpPzTxzu8f/OeEPaFA== + version "8.0.1" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-8.0.1.tgz#f86e89bbc925f2b068784b31f382afdc6ca56be1" + integrity sha512-BvEXF+UmsnAfYfoapKM9nGxnP+Wn7P91YfXmrKnfcYCx6VBeoN5Ez5Ogck6I8Bi5k4RlpqRYaw75pAwzX9OphA== dependencies: growly "^1.3.0" is-wsl "^2.2.0" @@ -11535,7 +11535,7 @@ semver@7.0.0: resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== -semver@7.3.2, semver@^7.2.1, semver@^7.3.2: +semver@7.3.2: version "7.3.2" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== @@ -11545,6 +11545,13 @@ semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^7.2.1, semver@^7.3.2: + version "7.3.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97" + integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw== + dependencies: + lru-cache "^6.0.0" + send@0.17.1: version "0.17.1" resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" @@ -13097,9 +13104,9 @@ uuid@^3.3.2, uuid@^3.4.0: integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== uuid@^8.3.0: - version "8.3.1" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.1.tgz#2ba2e6ca000da60fce5a196954ab241131e05a31" - integrity sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg== + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== v8-compile-cache@^2.0.3: version "2.1.1" From 25bfd5684cc1d13977866f0de3d04207824c5860 Mon Sep 17 00:00:00 2001 From: Jenni Laakso Date: Tue, 5 Jan 2021 15:23:53 +0200 Subject: [PATCH 07/15] Make sure verify API call succeeded before redirecting --- .../EmailVerificationPage.js | 16 ++++++++++------ .../EmailVerificationForm.js | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/containers/EmailVerificationPage/EmailVerificationPage.js b/src/containers/EmailVerificationPage/EmailVerificationPage.js index 846d304698..2bfe9d4d4c 100644 --- a/src/containers/EmailVerificationPage/EmailVerificationPage.js +++ b/src/containers/EmailVerificationPage/EmailVerificationPage.js @@ -1,5 +1,5 @@ import React from 'react'; -import PropTypes from 'prop-types'; +import { bool, func, shape, string } from 'prop-types'; import { compose } from 'redux'; import { connect } from 'react-redux'; import { withRouter } from 'react-router-dom'; @@ -51,6 +51,7 @@ export const EmailVerificationPageComponent = props => { intl, scrollingDisabled, submitVerification, + isVerified, emailVerificationInProgress, verificationError, location, @@ -62,9 +63,12 @@ export const EmailVerificationPageComponent = props => { const initialValues = { verificationToken: parseVerificationToken(location ? location.search : null), }; - const user = ensureCurrentUser(currentUser); - if (user && user.attributes.emailVerified) { + + // The first attempt to verify email is done when the page is loaded + // If the verify API call is successfull and the user has verified email + // We can redirect user forward from email verification page. + if (isVerified && user && user.attributes.emailVerified) { return ; } @@ -104,12 +108,11 @@ EmailVerificationPageComponent.defaultProps = { verificationError: null, }; -const { bool, func, shape, string } = PropTypes; - EmailVerificationPageComponent.propTypes = { currentUser: propTypes.currentUser, scrollingDisabled: bool.isRequired, submitVerification: func.isRequired, + isVerified: bool, emailVerificationInProgress: bool.isRequired, verificationError: propTypes.error, @@ -124,8 +127,9 @@ EmailVerificationPageComponent.propTypes = { const mapStateToProps = state => { const { currentUser } = state.user; - const { verificationError, verificationInProgress } = state.EmailVerification; + const { isVerified, verificationError, verificationInProgress } = state.EmailVerification; return { + isVerified, verificationError, emailVerificationInProgress: verificationInProgress, currentUser, diff --git a/src/forms/EmailVerificationForm/EmailVerificationForm.js b/src/forms/EmailVerificationForm/EmailVerificationForm.js index dea385b1d5..bffd021617 100644 --- a/src/forms/EmailVerificationForm/EmailVerificationForm.js +++ b/src/forms/EmailVerificationForm/EmailVerificationForm.js @@ -88,7 +88,7 @@ const EmailVerificationFormComponent = props => ( ); - return emailVerified && !pendingEmail ? alreadyVerified : verifyEmail; + return emailVerified && !pendingEmail && !verificationError ? alreadyVerified : verifyEmail; }} /> ); From 96b69a46d0d6f75d016f659c8f5c8da051dee409 Mon Sep 17 00:00:00 2001 From: Jenni Laakso Date: Tue, 5 Jan 2021 16:06:41 +0200 Subject: [PATCH 08/15] Update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e28f38aafe..d4432acd84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,10 @@ way to update this template, but currently, we follow a pattern: ## Upcoming version 2020-XX-XX +- [fix] Make sure that the verify email API endpoint has been called successfully before redirecting + the user away from EmailVerificationPage. + [#1397](https://github.com/sharetribe/ftw-daily/pull/1397) + ## [v7.2.0] 2020-12-16 - [add] Add helper functions for setting up your own OIDC authentication and using FTW server as From 50d57285482f9782439757cd58620bcb9a05d14c Mon Sep 17 00:00:00 2001 From: Jenni Laakso Date: Tue, 12 Jan 2021 15:23:14 +0200 Subject: [PATCH 09/15] Move .well-known/* endpoints from apiRouter to new wellKnownRouter --- server/apiRouter.js | 18 ------------------ server/apiServer.js | 2 ++ server/index.js | 11 +++++++++-- server/wellKnownRouter.js | 17 +++++++++++++++++ 4 files changed, 28 insertions(+), 20 deletions(-) create mode 100644 server/wellKnownRouter.js diff --git a/server/apiRouter.js b/server/apiRouter.js index 4618883639..c9a4b887eb 100644 --- a/server/apiRouter.js +++ b/server/apiRouter.js @@ -21,8 +21,6 @@ const createUserWithIdp = require('./api/auth/createUserWithIdp'); const { authenticateFacebook, authenticateFacebookCallback } = require('./api/auth/facebook'); const { authenticateGoogle, authenticateGoogleCallback } = require('./api/auth/google'); -const { openIdConfiguration, jwksUri } = require('./api-util/idToken'); - const router = express.Router(); // ================ API router middleware: ================ // @@ -82,20 +80,4 @@ router.get('/auth/google', authenticateGoogle); // loginWithIdp endpoint in Flex API to authenticate user to Flex router.get('/auth/google/callback', authenticateGoogleCallback); -// These endpoints will be used if you FTW as OIDC proxy -// https://www.sharetribe.com/docs/cookbook-social-logins-and-sso/setup-open-id-connect-proxy/ -// All identity providers should provide an OpenID Connect discovery document: -// https://openid.net/specs/openid-connect-discovery-1_0.html -// And in the discovery document we need to define jwks_uri attribute -// which denotes the location of public signing keys - -const rsaSecretKey = process.env.RSA_SECRET_KEY; -const rsaPublicKey = process.env.RSA_PUBLIC_KEY; -const keyId = process.env.KEY_ID; - -if (rsaPublicKey && rsaSecretKey) { - router.get('/.well-known/openid-configuration', openIdConfiguration); - router.get('/.well-known/jwks.json', jwksUri([{ alg: 'RS256', rsaPublicKey, keyId }])); -} - module.exports = router; diff --git a/server/apiServer.js b/server/apiServer.js index 6943df5913..237db4720d 100644 --- a/server/apiServer.js +++ b/server/apiServer.js @@ -9,6 +9,7 @@ const cookieParser = require('cookie-parser'); const bodyParser = require('body-parser'); const cors = require('cors'); const apiRouter = require('./apiRouter'); +const wellKnownRouter = require('./wellKnownRouter'); const radix = 10; const PORT = parseInt(process.env.REACT_APP_DEV_API_SERVER_PORT, radix); @@ -23,6 +24,7 @@ app.use( }) ); app.use(cookieParser()); +app.use('/.well-known', wellKnownRouter); app.use('/api', apiRouter); app.listen(PORT, () => { diff --git a/server/index.js b/server/index.js index 4de0265daa..ffb3133efd 100644 --- a/server/index.js +++ b/server/index.js @@ -33,6 +33,7 @@ const sitemap = require('express-sitemap'); const passport = require('passport'); const auth = require('./auth'); const apiRouter = require('./apiRouter'); +const wellKnownRouter = require('./wellKnownRouter'); const renderer = require('./renderer'); const dataLoader = require('./dataLoader'); const fs = require('fs'); @@ -131,9 +132,15 @@ app.use('/static', express.static(path.join(buildPath, 'static'))); app.use('/robots.txt', express.static(path.join(buildPath, 'robots.txt'))); app.use(cookieParser()); +// These .well-known/* endpoints will be enabled if you are using FTW as OIDC proxy +// https://www.sharetribe.com/docs/cookbook-social-logins-and-sso/setup-open-id-connect-proxy/ +// We need to handle these endpoints separately so that they are accessible by Flex +// even if you have enabled basic authentication e.g. in staging environment. +app.use('/.well-known', wellKnownRouter); + // Use basic authentication when not in dev mode. This is -// intentionally after the static middleware to skip basic auth for -// static resources. +// intentionally after the static middleware and /.well-known +// endpoints as those will bypass basic auth. if (!dev) { const USERNAME = process.env.BASIC_AUTH_USERNAME; const PASSWORD = process.env.BASIC_AUTH_PASSWORD; diff --git a/server/wellKnownRouter.js b/server/wellKnownRouter.js new file mode 100644 index 0000000000..1c6c8058c1 --- /dev/null +++ b/server/wellKnownRouter.js @@ -0,0 +1,17 @@ +const express = require('express'); +const { openIdConfiguration, jwksUri } = require('./api-util/idToken'); + +const rsaPrivateKey = process.env.RSA_PRIVATE_KEY; +const rsaPublicKey = process.env.RSA_PUBLIC_KEY; +const keyId = process.env.KEY_ID; + +const router = express.Router(); + +// These .well-known/* endpoints will be enabled if you are using FTW as OIDC proxy +// https://www.sharetribe.com/docs/cookbook-social-logins-and-sso/setup-open-id-connect-proxy/ +if (rsaPublicKey && rsaPrivateKey) { + router.get('/openid-configuration', openIdConfiguration); + router.get('/jwks.json', jwksUri([{ alg: 'RS256', rsaPublicKey, keyId }])); +} + +module.exports = router; From e5a72b296c0db4becd4166c4e8189cb825ca4d3c Mon Sep 17 00:00:00 2001 From: Jenni Laakso Date: Tue, 12 Jan 2021 15:28:50 +0200 Subject: [PATCH 10/15] Remove /api from issuerUrl in api-util/idToken.js --- server/api-util/idToken.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/api-util/idToken.js b/server/api-util/idToken.js index 9ee87664db..c5d57dc7ae 100644 --- a/server/api-util/idToken.js +++ b/server/api-util/idToken.js @@ -7,7 +7,7 @@ const PORT = parseInt(process.env.REACT_APP_DEV_API_SERVER_PORT, radix); const rootUrl = process.env.REACT_APP_CANONICAL_ROOT_URL; const useDevApiServer = process.env.NODE_ENV === 'development' && !!PORT; -const issuerUrl = useDevApiServer ? `http://localhost:${PORT}/api` : `${rootUrl}/api`; +const issuerUrl = useDevApiServer ? `http://localhost:${PORT}` : `${rootUrl}`; /** * Gets user information and creates the signed jwt for id token. From a73dca3ade943b9c73ba19c99210cf75714d39a8 Mon Sep 17 00:00:00 2001 From: Jenni Laakso Date: Tue, 12 Jan 2021 15:25:21 +0200 Subject: [PATCH 11/15] Update changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d4432acd84..06fa07b4ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,11 @@ way to update this template, but currently, we follow a pattern: ## Upcoming version 2020-XX-XX +- [fix] Move well-known/\* endpoints related to OIDC proxy setup from `apiRouter` to new + `wellKnownRouter`so that they can be enabled outside the basic auth setup. It also makes it + simpler to set the identity provider url, because we can drop the `/api` part of the path. Also, + rename the `RSA_SECRET_KEY`to `RSA_PRIVATE_KEY` for consistency. + [#1399](https://github.com/sharetribe/ftw-daily/pull/1399) - [fix] Make sure that the verify email API endpoint has been called successfully before redirecting the user away from EmailVerificationPage. [#1397](https://github.com/sharetribe/ftw-daily/pull/1397) From fc88476fb0c7e09dae0ddcc5509d469915997923 Mon Sep 17 00:00:00 2001 From: Jenni Laakso Date: Wed, 13 Jan 2021 10:39:15 +0200 Subject: [PATCH 12/15] Update changelog and package.json --- CHANGELOG.md | 4 ++++ package.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 06fa07b4ad..b5f6c60782 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ way to update this template, but currently, we follow a pattern: ## Upcoming version 2020-XX-XX +## [v7.3.0] 2021-01-13 + - [fix] Move well-known/\* endpoints related to OIDC proxy setup from `apiRouter` to new `wellKnownRouter`so that they can be enabled outside the basic auth setup. It also makes it simpler to set the identity provider url, because we can drop the `/api` part of the path. Also, @@ -23,6 +25,8 @@ way to update this template, but currently, we follow a pattern: the user away from EmailVerificationPage. [#1397](https://github.com/sharetribe/ftw-daily/pull/1397) + [v7.3.0]: https://github.com/sharetribe/ftw-daily/compare/v7.2.0...v7.3.0 + ## [v7.2.0] 2020-12-16 - [add] Add helper functions for setting up your own OIDC authentication and using FTW server as diff --git a/package.json b/package.json index 3c82f4abc1..59da6dc232 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "app", - "version": "7.2.0", + "version": "7.3.0", "private": true, "license": "Apache-2.0", "dependencies": { From 498de7117d42976098d1a695642fcb5e5134f462 Mon Sep 17 00:00:00 2001 From: Vesa Luusua Date: Thu, 21 Jan 2021 12:17:32 +0200 Subject: [PATCH 13/15] Note about omitting trailing slash --- .env-template | 1 + 1 file changed, 1 insertion(+) diff --git a/.env-template b/.env-template index 752a0f0437..7ab796c354 100644 --- a/.env-template +++ b/.env-template @@ -19,6 +19,7 @@ SHARETRIBE_SDK_CLIENT_SECRET= # REACT_APP_SHARETRIBE_MARKETPLACE_CURRENCY=USD +# Host/domain - don't use trailing slash: "/" REACT_APP_CANONICAL_ROOT_URL=http://localhost:3000 # Social logins && SSO From 8d8e7aef8e8c9d548db240c6f8238362dafe30e4 Mon Sep 17 00:00:00 2001 From: Vesa Luusua Date: Thu, 21 Jan 2021 12:21:21 +0200 Subject: [PATCH 14/15] Add a note about trailing slash to config script --- scripts/config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/config.js b/scripts/config.js index d74476ac5d..0f111c56f1 100644 --- a/scripts/config.js +++ b/scripts/config.js @@ -228,7 +228,7 @@ const advancedSettings = settings => { name: 'REACT_APP_CANONICAL_ROOT_URL', message: `What is your canonical root URL? ${chalk.dim( - 'Canonical root URL of the marketplace is needed for social media sharing and SEO optimization. When developing the template application locally URL is usually http://localhost:3000' + 'Canonical root URL of the marketplace is needed for social media sharing and SEO optimization. When developing the template application locally URL is usually http://localhost:3000 (Note: you should omit any trailing slash)' )} `, default: function() { From 230a080235bfd1cf783cc21b0836944bb8c11309 Mon Sep 17 00:00:00 2001 From: Vesa Luusua Date: Fri, 22 Jan 2021 09:51:11 +0200 Subject: [PATCH 15/15] Another update to config script --- scripts/config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/config.js b/scripts/config.js index 0f111c56f1..a74921923a 100644 --- a/scripts/config.js +++ b/scripts/config.js @@ -228,7 +228,7 @@ const advancedSettings = settings => { name: 'REACT_APP_CANONICAL_ROOT_URL', message: `What is your canonical root URL? ${chalk.dim( - 'Canonical root URL of the marketplace is needed for social media sharing and SEO optimization. When developing the template application locally URL is usually http://localhost:3000 (Note: you should omit any trailing slash)' + 'Canonical root URL of the marketplace is needed for social media sharing, SEO optimization, and social logins. When developing the template application locally URL is usually http://localhost:3000 (Note: you should omit any trailing slash)' )} `, default: function() {