Skip to content

Commit

Permalink
fix(login): Support login from protected URLs.
Browse files Browse the repository at this point in the history
Refactor processSignIn to use returnTo. Refactor accordingly.
  • Loading branch information
binh-dam-ibigroup committed Sep 21, 2020
1 parent 390f485 commit 2c962c4
Show file tree
Hide file tree
Showing 7 changed files with 39 additions and 36 deletions.
36 changes: 14 additions & 22 deletions lib/actions/auth.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { push } from 'connected-react-router'
import { replace, push } from 'connected-react-router'

import { setPathBeforeSignIn } from '../actions/user'

Expand Down Expand Up @@ -30,30 +30,22 @@ export function showLoginError (err) {
/**
* This function is called by the Auth0Provider component, with the described parameter(s),
* after the user signs in.
* @param {Object} appState The state that was stored when calling useAuth0().login().
* @param {Object} appState The state stored when calling useAuth0().loginWithRedirect
* or a withAuhenticationRequired-enabled component.
*/
export function processSignIn (appState) {
return function (dispatch, getState) {
if (appState && appState.urlHash) {
// At this stage after login, Auth0 has already redirected to /signedin (Auth0-whitelisted)
// which shows the AfterLoginScreen.
//
// Here, we save the URL hash prior to login (contains a combination of itinerary search, stop/trip view, etc.),
// so that the AfterLoginScreen can redirect back there when logged-in user info is fetched.
// (For routing, it is easier to deal with the path without the hash sign.)
const hashIndex = appState.urlHash.indexOf('#')
const urlHashWithoutHash = hashIndex >= 0
? appState.urlHash.substr(hashIndex + 1)
: '/'
dispatch(setPathBeforeSignIn(urlHashWithoutHash))
} else if (appState && appState.returnTo) {
// TODO: Handle other after-login situations.
// Note that when redirecting from a login-protected (e.g. account) page while logged out,
// then returnTo is set by Auth0 to this object format:
// {
// pathname: "/"
// query: { ... }
// }
if (appState && appState.returnTo) {
// Remove URL parameters that were added by auth0-react
// (see https://github.com/auth0/auth0-react/blob/adac2e810d4f6d33253cb8b2016fcedb98a3bc16/examples/cra-react-router/src/index.tsx#L7)
window.history.replaceState({}, '', window.location.pathname)

// Here, we add to the redux state the URL route (portion after # that contains the route/page name e.g. /account,
// and includes a combination of itinerary search, stop/trip view, etc.) that was passed to appState prior to login,
// and we redirect to the "/signedin" route, where the AfterLoginScreen
// will fetch the user data and, upon fetched, redirect back to appState.returnTo.
dispatch(setPathBeforeSignIn(appState.returnTo))
dispatch(replace('/signedin'))
}
}
}
4 changes: 2 additions & 2 deletions lib/components/app/responsive-webapp.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { getCurrentPosition, receivedPositionResponse } from '../../actions/loca
import { setLocationToCurrent } from '../../actions/map'
import { handleBackButtonPress, matchContentToUrl } from '../../actions/ui'
import { getAuth0Config } from '../../util/auth'
import { AUTH0_AUDIENCE, AUTH0_SCOPE, URL_ROOT } from '../../util/constants'
import { AUTH0_AUDIENCE, AUTH0_SCOPE } from '../../util/constants'
import { getActiveItinerary, getTitle } from '../../util/state'
import AfterSignInScreen from '../user/after-signin-screen'
import BeforeSignInScreen from '../user/before-signin-screen'
Expand Down Expand Up @@ -291,7 +291,7 @@ class RouterWrapperWithAuth0 extends Component {
onLoginError={showLoginError}
onRedirectCallback={processSignIn}
onRedirecting={BeforeSignInScreen}
redirectUri={URL_ROOT}
redirectUri={window.location.origin}
scope={AUTH0_SCOPE}
>
{router}
Expand Down
8 changes: 2 additions & 6 deletions lib/components/user/nav-login-button-auth0.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useAuth0 } from '@auth0/auth0-react'
import React from 'react'

import { URL_ROOT } from '../../util/constants'
import NavLoginButton from './nav-login-button'

/**
Expand All @@ -16,14 +15,11 @@ const NavLoginButtonAuth0 = ({
const { isAuthenticated, loginWithRedirect, logout, user } = useAuth0()

// On login, preserve the current trip query if any.
// After login, redirect to a whitelisted URL in the Auth0 dashboard.
const afterLoginPath = '/#/signedin'
const handleLogin = () => loginWithRedirect({
redirectUri: `${URL_ROOT}${afterLoginPath}`,
appState: {urlHash: window.location.hash} // The part of href from #/?, e.g. #/?ui_activeSearch=...
appState: { returnTo: window.location.hash.substr(1) } // e.g. /?ui_activeSearch=... without #.
})
const handleLogout = () => logout({
returnTo: URL_ROOT
returnTo: window.location.origin
})

// On logout, it is better to "clear" the screen, so
Expand Down
8 changes: 7 additions & 1 deletion lib/components/user/saved-trip-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ const mapDispatchToProps = {
}

export default withLoggedInUserSupport(
withAuthenticationRequired(connect(mapStateToProps, mapDispatchToProps)(SavedTripList)),
withAuthenticationRequired(
connect(mapStateToProps, mapDispatchToProps)(SavedTripList),
{
// Redirect back to this page if a user logs in from the "my trips" URL.
returnTo: () => window.location.hash.substr(1)
}
),
true
)
8 changes: 7 additions & 1 deletion lib/components/user/saved-trip-screen.js
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,12 @@ const mapDispatchToProps = {
}

export default withLoggedInUserSupport(
withAuthenticationRequired(connect(mapStateToProps, mapDispatchToProps)(SavedTripScreen)),
withAuthenticationRequired(
connect(mapStateToProps, mapDispatchToProps)(SavedTripScreen),
{
// Redirect back to this page if a user logs in from the URL for saving a trip.
returnTo: () => window.location.hash.substr(1)
}
),
true
)
8 changes: 7 additions & 1 deletion lib/components/user/user-account-screen.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,12 @@ const mapDispatchToProps = {
}

export default withLoggedInUserSupport(
withAuthenticationRequired(connect(mapStateToProps, mapDispatchToProps)(UserAccountScreen)),
withAuthenticationRequired(
connect(mapStateToProps, mapDispatchToProps)(UserAccountScreen),
{
// Redirect back to this page if a user logs in from the account URL.
returnTo: () => window.location.hash.substr(1)
}
),
true
)
3 changes: 0 additions & 3 deletions lib/util/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,3 @@ export const AUTH0_AUDIENCE = 'https://otp-middleware'
export const AUTH0_SCOPE = ''
export const DEFAULT_APP_TITLE = 'OpenTripPlanner'
export const PERSISTENCE_STRATEGY_OTP_MIDDLEWARE = 'otp_middleware'

// Gets the root URL, e.g. https://otp-instance.example.com:8080, computed once for all.
export const URL_ROOT = `${window.location.protocol}//${window.location.host}`

0 comments on commit 2c962c4

Please sign in to comment.