Skip to content

Commit

Permalink
CCM-5100: Improved handling of redirects
Browse files Browse the repository at this point in the history
  • Loading branch information
m-houston committed Jun 28, 2024
1 parent acac2a1 commit b1cfe69
Show file tree
Hide file tree
Showing 9 changed files with 163 additions and 96 deletions.
61 changes: 9 additions & 52 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,75 +1,34 @@
'use client';

import ConfigureAmplifyClientSide from '../components/ConfigureAmplify';

import React from 'react';
import { Authenticator, Heading, useTheme } from '@aws-amplify/ui-react';
import { Authenticator } from '@aws-amplify/ui-react';
import '@aws-amplify/ui-react/styles.css';
import { Col, Container, Footer, Header, Row } from 'nhsuk-react-components';

import ConfigureAmplifyClientSide from '../components/ConfigureAmplify';
import LoginStatus from '../components/LoginStatus';

import 'nhsuk-frontend/dist/nhsuk.css';
import './styles.css';
import Logout from '../components/Logout';
import { signInWithRedirect } from '@aws-amplify/auth';
import { Amplify } from 'aws-amplify';

export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {

async function auth0Login() {
console.log(Amplify.getConfig());
await signInWithRedirect({
provider: {
custom: 'Auth0'
}
})
}

const components = {
SignIn: {
Header() {
const { tokens } = useTheme();

return (<>
<Heading
padding={`${tokens.space.xl} 0 0 ${tokens.space.xl}`}
level={3}
>
Sign in to your account
</Heading>
<button onClick={auth0Login}>Log in with Auth0</button>
</>
);
}
}
};

export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<Authenticator.Provider>
<ConfigureAmplifyClientSide />
<Header transactional>
<Header serviceName="Notify">
<Header.Container>
<Header.Logo href="/" />
<Header.ServiceName href="/">
Notify
</Header.ServiceName>
<Header.Content>
<Logout />
<LoginStatus />
</Header.Content>
</Header.Container>
<Header.Nav>
{/*<Header.NavItem href="/conditions">*/}
{/* Health A-Z*/}
{/*</Header.NavItem>*/}
<Header.NavItem
home
href="/"
>
<Header.NavItem home href="/">
Home
</Header.NavItem>
<Header.NavDropdownMenu />
Expand All @@ -79,9 +38,7 @@ export default function RootLayout({
<main className="nhsuk-main-wrapper" id="maincontent" role="main">
<Row>
<Col width="full">
<Authenticator hideSignUp components={components}>
{children}
</Authenticator>
{children}
</Col>
</Row>
</main>
Expand Down
36 changes: 28 additions & 8 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,36 @@
import React from 'react';
import Redirect from '../components/Redirect';
'use client';

export default async function Page({ searchParams }: {
import React, { useEffect, useState } from 'react';
import { Hub } from '@aws-amplify/core';
import Login from '../components/Login';

export default function Page({ searchParams }: {
searchParams: { [key: string]: string | string[] | undefined }
}) {

const redirectPath = [searchParams.redirect].flat().pop() || '/';
if (!redirectPath.match(/^\/[a-z/]*$/)) {
const [redirect, setRedirect] = useState<string | undefined>();

useEffect(() => {
return Hub.listen('auth', ({ payload }) => {
switch (payload.event) {
case 'customOAuthState':
try {
const { redirectPath } = JSON.parse(payload.data);
setRedirect(redirectPath);
} catch (err) {
console.error(err);
setRedirect('Invalid redirect path');
}
break;
}
});
}, []);

let redirectPath = redirect || [searchParams.redirect].flat().pop() || '/';
if (redirectPath === '/auth') redirectPath = '/';
if (redirectPath && !redirectPath.match(/^\/[a-z/]*$/)) {
return <h2>Invalid redirect path</h2>;
}

return <>
<Redirect path={redirectPath} />
</>
return <Login redirectPath={redirectPath} />
}
18 changes: 18 additions & 0 deletions app/signout/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react';
import { AuthGetCurrentUserServer } from '../../utils/amplify-utils';
import Logout from '../../components/Logout';
import { redirect } from 'next/navigation';

export default async function Page() {

const { currentUser, attributes } = await AuthGetCurrentUserServer() ?? {};
if (!currentUser) {
redirect('/');
}

return <>
<h1>Sign out</h1>
<p>You are currently logged in as <strong>{attributes?.email}</strong></p>
<Logout />
</>
}
5 changes: 0 additions & 5 deletions app/status/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,7 @@ export default async function Page({ searchParams }: {
searchParams: { [key: string]: string | string[] | undefined }
}) {

// Client side user lookup
// const { user, signOut } = useAuthenticator((context) => [context.user]);

// Server side lookup
const { currentUser, attributes } = await AuthGetCurrentUserServer() ?? {};

const redirectPath = [searchParams.redirect].flat().pop() || '/';

return <>
Expand Down
9 changes: 9 additions & 0 deletions app/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,12 @@
flex-grow: 100;
text-align: right;
}

div.nhsuk-header__content > li.nhsuk-header__navigation-item {
list-style: none;
}

div.nhsuk-header__content > li.nhsuk-header__navigation-item > a {
padding: 0;
display: inline-block;
}
75 changes: 75 additions & 0 deletions components/Login.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
'use client';

import { Heading, useTheme, withAuthenticator } from '@aws-amplify/ui-react';
import { AuthUser } from 'aws-amplify/auth';
import React, { useEffect } from 'react';
import { Amplify } from 'aws-amplify';
import { signInWithRedirect } from '@aws-amplify/auth';
import { Button } from 'nhsuk-react-components';
import {
DefaultComponents
} from '@aws-amplify/ui-react/dist/types/components/Authenticator/hooks/useCustomComponents/defaultComponents';

function auth0Login(redirectPath: string) {
console.log(Amplify.getConfig());
signInWithRedirect({
provider: {
custom: 'Auth0'
},
customState: JSON.stringify({ redirectPath })
}).catch(console.error);
}

function components(redirectPath: string): DefaultComponents {
return {

SignIn: {
Header() {
const { tokens } = useTheme();

return (<>
<Heading
padding={`${tokens.space.xl} 0 0 ${tokens.space.xl}`}
level={3}
>
Sign in to your account
</Heading>
<div className="login-oidc"
style={{
position: 'relative',
padding: `${tokens.space.xl} ${tokens.space.xl} 0 ${tokens.space.xl}` }}>
<Button
className="login-oidc__button"
style={{width: '100%'}}
onClick={() => auth0Login(redirectPath)}>Log in with Auth0</Button>
</div>
<div style={{textAlign:'center'}}>
or
</div>
</>
);
}
}
}
};

function Login({ user, redirectPath }: { user?: AuthUser, redirectPath?: string }) {
useEffect(() => {
if (user && redirectPath) {
location.href = redirectPath;
}
}, [user, redirectPath]);
if (redirectPath && user) {
return <h3>Redirecting to <code><a href={redirectPath}>{redirectPath}</a></code></h3>;
}
return null;
}

export default (props: { redirectPath?: string; user?: AuthUser }) => {
const { redirectPath } = props;
return withAuthenticator(Login, {
variation: 'default',
hideSignUp: true,
components: components(redirectPath || '/')
})(props);
};
21 changes: 21 additions & 0 deletions components/LoginStatus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
'use client';

import { Header } from 'nhsuk-react-components';
import React from 'react';
import { useAuthenticator } from '@aws-amplify/ui-react';

export default function LoginStatus() {
const { authStatus } = useAuthenticator();
switch (authStatus) {
case 'authenticated':
return <Header.NavItem href="/auth/signout">
Sign out
</Header.NavItem>;
case 'unauthenticated':
return <Header.NavItem href={`/auth/?redirect=${location.pathname}`}>
Sign in
</Header.NavItem>;
default:
return null;
}
}
14 changes: 3 additions & 11 deletions components/Logout.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,15 @@
'use client';

import { useRouter } from 'next/navigation';
import { useAuthenticator } from '@aws-amplify/ui-react';
import { Button } from 'nhsuk-react-components';

export default function Logout() {
const router = useRouter();
const { user, signOut } = useAuthenticator();
const { authStatus, signOut } = useAuthenticator();

async function handleSignOut() {
signOut();
location.href = '/';
}

return user ? (
<button
onClick={handleSignOut}
className="px-2 bg-white text-black"
>
Sign out
</button>
) : [];
return <Button onClick={handleSignOut}>Sign out</Button>;
}
20 changes: 0 additions & 20 deletions components/Redirect.tsx

This file was deleted.

0 comments on commit b1cfe69

Please sign in to comment.