Skip to content

Commit

Permalink
feat(auth): add unauthorized error page
Browse files Browse the repository at this point in the history
Signed-off-by: Petr Kadlec <[email protected]>
  • Loading branch information
kapetr committed Oct 17, 2024
1 parent b6c51c5 commit 24ae590
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 0 deletions.
9 changes: 9 additions & 0 deletions src/app/auth/signin/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ import { LoginError, SignIn } from '@/modules/auth/SignIn';
import { isAbsoluteUrl } from '@/utils/url';
import { useMemo } from 'react';
import { signIn } from './actions';
import { redirect } from 'next/navigation';

const DUMMY_JWT_TOKEN = process.env.DUMMY_JWT_TOKEN!;

interface PageProps {
searchParams: Record<string, string | string[] | undefined>;
Expand All @@ -35,6 +38,12 @@ export default function SignInPage({ searchParams }: PageProps) {
? searchParams.error[0]
: (searchParams.error ?? null);

if (DUMMY_JWT_TOKEN)
// user shouldn't be here, let's redirect him to the error page
redirect(
`/auth/unauthorized?${new URLSearchParams({ error: errorCode ?? '' }).toString()}`,
);

const error: LoginError | null = useMemo(() => {
switch (errorCode) {
case null:
Expand Down
47 changes: 47 additions & 0 deletions src/app/auth/unauthorized/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* Copyright 2024 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { LoginError } from '@/modules/auth/SignIn';
import { useMemo } from 'react';
import { Unauthorized } from '@/modules/auth/Unauthorized';

interface PageProps {
searchParams: Record<string, string | string[] | undefined>;
}

export default function SignInPage({ searchParams }: PageProps) {
const errorCode = Array.isArray(searchParams.error)
? searchParams.error[0]
: (searchParams.error ?? null);

const error: LoginError | null = useMemo(() => {
switch (errorCode) {
case 'service_unavailable':
return {
kind: 'error',
title: 'The API server is probably unavailable.',
};
default:
return {
kind: 'error',
title:
"You either requested the resource you're not authorized to access or this could be due to a mismatch in your environment variables on either the API or UI.",
};
}
}, [errorCode]);

return <Unauthorized error={error} />;
}
4 changes: 4 additions & 0 deletions src/modules/auth/SignIn.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,7 @@
.versionTag {
margin-inline-start: $spacing-03;
}

.unauthCtaButton {
margin-block-start: $spacing-05;
}
49 changes: 49 additions & 0 deletions src/modules/auth/Unauthorized.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* Copyright 2024 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use client';
import { Button, InlineNotification } from '@carbon/react';
import { ArrowRight } from '@carbon/react/icons';
import classes from './SignIn.module.scss';
import { useRouter } from 'next-nprogress-bar';
import { PROJECT_ID_DEFAULT } from '@/utils/constants';
import { LoginError } from './SignIn';

interface Props {
error: LoginError | null;
}

export function Unauthorized({ error }: Props) {
const router = useRouter();
return (
<div className={classes.root}>
<div className={classes.loginGrid}>
<div className={classes.content}>
<h1 className={classes.heading}>Unauthorized</h1>
{error != null && <p>{error.title}</p>}

<Button
renderIcon={ArrowRight}
className={classes.unauthCtaButton}
onClick={() => router.push(`/${PROJECT_ID_DEFAULT}`)}
>
Go to the default workspace
</Button>
</div>
</div>
</div>
);
}

0 comments on commit 24ae590

Please sign in to comment.