diff --git a/src/browser/modules/Stream/Auth/ConnectForm.tsx b/src/browser/modules/Stream/Auth/ConnectForm.tsx index 22fdf1d762f..878f83c63b6 100644 --- a/src/browser/modules/Stream/Auth/ConnectForm.tsx +++ b/src/browser/modules/Stream/Auth/ConnectForm.tsx @@ -392,13 +392,15 @@ export default function ConnectForm(props: ConnectFormProps): JSX.Element { {props.authenticationMethod === SSO && !SSOLoading && (SSOError || SSORedirectError) && ( - - ERROR -
{SSOError || SSORedirectError}
+ <> + + ERROR +
{SSOError || SSORedirectError}
+
- Download logs + Download browser SSO logs -
+ )} {props.connecting diff --git a/src/browser/modules/Stream/Auth/styled.tsx b/src/browser/modules/Stream/Auth/styled.tsx index 703c0d9ff94..8a912fa55fd 100644 --- a/src/browser/modules/Stream/Auth/styled.tsx +++ b/src/browser/modules/Stream/Auth/styled.tsx @@ -152,9 +152,27 @@ export const StyledDbsRow = styled.li`` export const StyledFormContainer = styled.div` display: flex; ` -export const StyledSSOLogDownload = styled.a` +export const StyledSSOLogDownload = styled.button` + color: ${props => props.theme.primaryButtonText}; + background-color: ${props => props.theme.primary}; + border: 1px solid ${props => props.theme.primary}; + font-family: ${props => props.theme.primaryFontFamily}; + padding: 6px 18px; + font-weight: 600; + font-size: 14px; + text-align: center; + vertical-align: middle; cursor: pointer; + border-radius: 4px; + line-height: 20px; + + &:hover { + background-color: ${props => props.theme.primary50}; + color: ${props => props.theme.secondaryButtonTextHover}; + border: 1px solid ${props => props.theme.primary50}; + } ` + export const StyledSSOButtonContainer = styled.div` margin-bottom: 12px; ` @@ -162,4 +180,5 @@ export const StyledSSOError = styled.div` margin-top: 30px; padding: 3px; white-space: pre-line; + display: flex; ` diff --git a/src/shared/modules/connections/connectionsDuck.ts b/src/shared/modules/connections/connectionsDuck.ts index f4b68260576..866f7aa9841 100644 --- a/src/shared/modules/connections/connectionsDuck.ts +++ b/src/shared/modules/connections/connectionsDuck.ts @@ -561,6 +561,11 @@ export const startupConnectEpic = (action$: any, store: any) => { resolve({ type: STARTUP_CONNECTION_SUCCESS }) }) .catch(() => { + if (discovered.attemptSSOLogin) { + authLog( + 'client side SSO flow completed but Neo4j Browser failed to connect to neo4j. Server side logs (security.log or debug.log) may contain more information.' + ) + } store.dispatch(setActiveConnection(null)) store.dispatch( discovery.updateDiscoveryConnection({ @@ -694,6 +699,12 @@ export const connectionLostEpic = (action$: any, store: any) => ) } catch (e) { authLog(`Failed to refresh token: ${e}`) + authLog( + 'This could be due to the refresh token not being available, which happens if Neo4j Browser accessed via stored credentials rather than redoing the SSO flow. ' + + 'If you have a short lived access token, it may be beneficial to set `browser.retain_connection_credentials=false` in neo4j.conf to make sure the refresh token is always available.' + ) + // if refreshing the token failed, don't retry + return resolve({ type: UnauthorizedDriverError }) } } } else {