Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SDK-2586] Add user to withPageAuthRequiredProps CSR to match SSR #405

Merged
merged 1 commit into from
Jun 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
24 changes: 4 additions & 20 deletions examples/kitchen-sink-example/pages/profile.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,14 @@
import React from 'react';
import { useUser, withPageAuthRequired } from '@auth0/nextjs-auth0';
import { withPageAuthRequired } from '@auth0/nextjs-auth0';

import Layout from '../components/layout';

export default withPageAuthRequired(function Profile(): React.ReactElement {
const { user, error, isLoading } = useUser();

export default withPageAuthRequired(function Profile({ user }) {
return (
<Layout>
<h1>Profile</h1>

{isLoading && <p>Loading profile...</p>}

{error && (
<>
<h4>Error</h4>
<pre>{error.message}</pre>
</>
)}

{user && (
<>
<h4>Profile</h4>
<pre data-testid="profile">{JSON.stringify(user, null, 2)}</pre>
</>
)}
<h4>Profile</h4>
<pre data-testid="profile">{JSON.stringify(user, null, 2)}</pre>
</Layout>
);
});
7 changes: 6 additions & 1 deletion src/frontend/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
export { default as ConfigProvider, ConfigProviderProps, useConfig } from './use-config';
export { default as UserProvider, UserProviderProps, UserProfile, UserContext, useUser } from './use-user';
export { default as withPageAuthRequired, WithPageAuthRequired } from './with-page-auth-required';
export {
default as withPageAuthRequired,
WithPageAuthRequired,
WithPageAuthRequiredProps,
WithPageAuthRequiredOptions
} from './with-page-auth-required';
17 changes: 12 additions & 5 deletions src/frontend/with-page-auth-required.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { ComponentType, useEffect } from 'react';

import { useConfig } from './use-config';
import { useUser } from './use-user';
import { useUser, UserProfile } from './use-user';

/**
* @ignore
Expand Down Expand Up @@ -51,6 +51,14 @@ export interface WithPageAuthRequiredOptions {
onError?: (error: Error) => JSX.Element;
}

/**
* @ignore
*/
export interface WithPageAuthRequiredProps {
user: UserProfile;
[key: string]: any;
}

/**
* ```js
* const MyProtectedPage = withPageAuthRequired(MyPage);
Expand All @@ -61,11 +69,10 @@ export interface WithPageAuthRequiredOptions {
*
* @category Client
*/
// eslint-disable-next-line @typescript-eslint/ban-types
export type WithPageAuthRequired = <P extends object>(
export type WithPageAuthRequired = <P extends WithPageAuthRequiredProps>(
Component: ComponentType<P>,
options?: WithPageAuthRequiredOptions
) => React.FC<P>;
) => React.FC<Omit<P, 'user'>>;

/**
* @ignore
Expand All @@ -91,7 +98,7 @@ const withPageAuthRequired: WithPageAuthRequired = (Component, options = {}) =>
}, [user, error, isLoading]);

if (error) return onError(error);
if (user) return <Component {...props} />;
if (user) return <Component user={user} {...(props as any)} />;

return onRedirecting();
};
Expand Down
9 changes: 6 additions & 3 deletions src/helpers/with-page-auth-required.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import { GetServerSideProps, GetServerSidePropsContext, GetServerSidePropsResult
import { Claims, GetSession } from '../session';
import { assertCtx } from '../utils/assert';
import React, { ComponentType } from 'react';
import { WithPageAuthRequiredOptions as WithPageAuthRequiredCSROptions } from '../frontend/with-page-auth-required';
import {
WithPageAuthRequiredOptions as WithPageAuthRequiredCSROptions,
WithPageAuthRequiredProps
} from '../frontend/with-page-auth-required';
import { withPageAuthRequired as withPageAuthRequiredCSR } from '../frontend';

/**
Expand Down Expand Up @@ -81,7 +84,7 @@ export type WithPageAuthRequiredOptions = { getServerSideProps?: GetServerSidePr
*/
export type WithPageAuthRequired = {
(opts?: WithPageAuthRequiredOptions): PageRoute;
<P extends { [key: string]: any }>(
<P extends WithPageAuthRequiredProps>(
Component: ComponentType<P>,
options?: WithPageAuthRequiredCSROptions
): React.FC<P>;
Expand All @@ -92,7 +95,7 @@ export type WithPageAuthRequired = {
*/
export default function withPageAuthRequiredFactory(loginUrl: string, getSession: GetSession): WithPageAuthRequired {
return (
optsOrComponent: WithPageAuthRequiredOptions | ComponentType = {},
optsOrComponent: WithPageAuthRequiredOptions | ComponentType<WithPageAuthRequiredProps> = {},
csrOpts?: WithPageAuthRequiredCSROptions
): any => {
if (typeof optsOrComponent === 'function') {
Expand Down
12 changes: 9 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,15 +99,21 @@ export const initAuth0: InitAuth0 = (params) => {
export const getSession: GetSession = (...args) => getInstance().getSession(...args);
export const getAccessToken: GetAccessToken = (...args) => getInstance().getAccessToken(...args);
export const withApiAuthRequired: WithApiAuthRequired = (...args) => getInstance().withApiAuthRequired(...args);
export const withPageAuthRequired: WithPageAuthRequired = (...args: any[]): any =>
withPageAuthRequiredFactory(getLoginUrl(), getSession)(...args);
export const withPageAuthRequired: WithPageAuthRequired = withPageAuthRequiredFactory(getLoginUrl(), getSession);
export const handleLogin: HandleLogin = (...args) => getInstance().handleLogin(...args);
export const handleLogout: HandleLogout = (...args) => getInstance().handleLogout(...args);
export const handleCallback: HandleCallback = (...args) => getInstance().handleCallback(...args);
export const handleProfile: HandleProfile = (...args) => getInstance().handleProfile(...args);
export const handleAuth: HandleAuth = (...args) => getInstance().handleAuth(...args);

export { UserProvider, UserProviderProps, UserProfile, UserContext, useUser } from './frontend';
export {
UserProvider,
UserProviderProps,
UserProfile,
UserContext,
useUser,
WithPageAuthRequiredProps
} from './frontend';

export {
ConfigParameters,
Expand Down
7 changes: 3 additions & 4 deletions tests/frontend/with-page-auth-required.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,12 @@ describe('with-page-auth-required csr', () => {
await waitFor(() => expect(screen.queryByText('Private')).not.toBeInTheDocument());
});

it('should allow access to a CSR page when authenticated', async () => {
const MyPage = (): JSX.Element => <>Private</>;
const ProtectedPage = withPageAuthRequired(MyPage);
it('should add user to props of CSR page when authenticated', async () => {
const ProtectedPage = withPageAuthRequired(({ user }): JSX.Element => <>{user.email}</>);

render(<ProtectedPage />, { wrapper: withUserProvider({ user }) });
await waitFor(() => expect(window.location.assign).not.toHaveBeenCalled());
await waitFor(() => expect(screen.getByText('Private')).toBeInTheDocument());
await waitFor(() => expect(screen.getByText('foo@example.com')).toBeInTheDocument());
});

it('should show an empty element when redirecting', async () => {
Expand Down