diff --git a/examples/api-call-example/components/login-redirect.jsx b/examples/api-call-example/components/login-redirect.jsx
index 0f6e1baee..284265231 100644
--- a/examples/api-call-example/components/login-redirect.jsx
+++ b/examples/api-call-example/components/login-redirect.jsx
@@ -1,19 +1,11 @@
-import Router from 'next/router';
-import React, { Component } from 'react';
+import React from 'react';
-import Layout from '../components/layout';
-import createLoginUrl from '../lib/url-helper';
+import Layout from './layout';
-export default class RedirectToLogin extends Component {
- componentDidMount() {
- window.location.assign(createLoginUrl(Router.pathname));
- }
+const LoginRedirect = () => (
+
+ Signing you in...
+
+);
- render() {
- return (
-
- Signing you in...
-
- );
- }
-}
+export default LoginRedirect;
diff --git a/examples/api-call-example/components/with-auth.jsx b/examples/api-call-example/components/with-auth.jsx
deleted file mode 100644
index 6d82afc17..000000000
--- a/examples/api-call-example/components/with-auth.jsx
+++ /dev/null
@@ -1,42 +0,0 @@
-import React from 'react';
-import { useUser } from '@auth0/nextjs-auth0';
-
-import auth0 from '../lib/auth0';
-import createLoginUrl from '../lib/url-helper';
-import RedirectToLogin from '../components/login-redirect';
-
-export default function withAuth(InnerComponent) {
- const Authenticated = (props) => {
- const { user } = useUser();
-
- if (!user) {
- return ; // do you need a "redirecting to login" route?
- }
-
- return ;
- };
-
- Authenticated.getInitialProps = async (ctx) => {
- if (!ctx.req) {
- const response = await fetch('/api/me');
- const result = response.ok ? await response.json() : null;
-
- return { user: result };
- }
-
- const session = await auth0.getSession(ctx.req, ctx.res);
-
- if (!session || !session.user) {
- ctx.res.writeHead(302, {
- Location: createLoginUrl(ctx.req.url)
- });
- ctx.res.end();
-
- return;
- }
-
- return { user: session.user };
- };
-
- return Authenticated;
-}
diff --git a/examples/api-call-example/lib/url-helper.js b/examples/api-call-example/lib/url-helper.js
deleted file mode 100644
index 6512fdbc9..000000000
--- a/examples/api-call-example/lib/url-helper.js
+++ /dev/null
@@ -1,6 +0,0 @@
-export default function createLoginUrl(redirectTo) {
- if (redirectTo) {
- return `/api/login?redirectTo=${encodeURIComponent(redirectTo)}`;
- }
- return `/api/login`;
-}
diff --git a/examples/api-call-example/pages/profile-ssr.jsx b/examples/api-call-example/pages/profile-ssr.jsx
index 66246b2f8..365160404 100644
--- a/examples/api-call-example/pages/profile-ssr.jsx
+++ b/examples/api-call-example/pages/profile-ssr.jsx
@@ -1,7 +1,9 @@
import React from 'react';
+import { withAuth } from '@auth0/nextjs-auth0';
import Layout from '../components/layout';
-import withAuth from '../components/with-auth';
+import LoginRedirect from '../components/login-redirect';
+import auth0 from '../lib/auth0';
const Profile = ({ user }) => (
@@ -14,4 +16,4 @@ const Profile = ({ user }) => (
);
-export default withAuth(Profile);
+export default withAuth(Profile, LoginRedirect, auth0);
diff --git a/examples/api-call-example/pages/protected-page.jsx b/examples/api-call-example/pages/protected-page.jsx
index 9df18ab85..a11b76959 100644
--- a/examples/api-call-example/pages/protected-page.jsx
+++ b/examples/api-call-example/pages/protected-page.jsx
@@ -1,8 +1,9 @@
import React from 'react';
-import { useUser } from '@auth0/nextjs-auth0';
+import { useUser, withAuth } from '@auth0/nextjs-auth0';
import Layout from '../components/layout';
-import withAuth from '../components/with-auth';
+import LoginRedirect from '../components/login-redirect';
+import auth0 from '../lib/auth0';
export function ProtectedPage() {
const { user, loading } = useUser();
@@ -23,4 +24,4 @@ export function ProtectedPage() {
);
}
-export default withAuth(ProtectedPage);
+export default withAuth(ProtectedPage, LoginRedirect, auth0);
diff --git a/examples/basic-example/components/login-redirect.jsx b/examples/basic-example/components/login-redirect.jsx
index 0f6e1baee..284265231 100644
--- a/examples/basic-example/components/login-redirect.jsx
+++ b/examples/basic-example/components/login-redirect.jsx
@@ -1,19 +1,11 @@
-import Router from 'next/router';
-import React, { Component } from 'react';
+import React from 'react';
-import Layout from '../components/layout';
-import createLoginUrl from '../lib/url-helper';
+import Layout from './layout';
-export default class RedirectToLogin extends Component {
- componentDidMount() {
- window.location.assign(createLoginUrl(Router.pathname));
- }
+const LoginRedirect = () => (
+
+ Signing you in...
+
+);
- render() {
- return (
-
- Signing you in...
-
- );
- }
-}
+export default LoginRedirect;
diff --git a/examples/basic-example/components/with-auth.jsx b/examples/basic-example/components/with-auth.jsx
deleted file mode 100644
index 6d82afc17..000000000
--- a/examples/basic-example/components/with-auth.jsx
+++ /dev/null
@@ -1,42 +0,0 @@
-import React from 'react';
-import { useUser } from '@auth0/nextjs-auth0';
-
-import auth0 from '../lib/auth0';
-import createLoginUrl from '../lib/url-helper';
-import RedirectToLogin from '../components/login-redirect';
-
-export default function withAuth(InnerComponent) {
- const Authenticated = (props) => {
- const { user } = useUser();
-
- if (!user) {
- return ; // do you need a "redirecting to login" route?
- }
-
- return ;
- };
-
- Authenticated.getInitialProps = async (ctx) => {
- if (!ctx.req) {
- const response = await fetch('/api/me');
- const result = response.ok ? await response.json() : null;
-
- return { user: result };
- }
-
- const session = await auth0.getSession(ctx.req, ctx.res);
-
- if (!session || !session.user) {
- ctx.res.writeHead(302, {
- Location: createLoginUrl(ctx.req.url)
- });
- ctx.res.end();
-
- return;
- }
-
- return { user: session.user };
- };
-
- return Authenticated;
-}
diff --git a/examples/basic-example/lib/url-helper.js b/examples/basic-example/lib/url-helper.js
deleted file mode 100644
index 6512fdbc9..000000000
--- a/examples/basic-example/lib/url-helper.js
+++ /dev/null
@@ -1,6 +0,0 @@
-export default function createLoginUrl(redirectTo) {
- if (redirectTo) {
- return `/api/login?redirectTo=${encodeURIComponent(redirectTo)}`;
- }
- return `/api/login`;
-}
diff --git a/examples/basic-example/pages/profile-ssr.jsx b/examples/basic-example/pages/profile-ssr.jsx
index 66246b2f8..365160404 100644
--- a/examples/basic-example/pages/profile-ssr.jsx
+++ b/examples/basic-example/pages/profile-ssr.jsx
@@ -1,7 +1,9 @@
import React from 'react';
+import { withAuth } from '@auth0/nextjs-auth0';
import Layout from '../components/layout';
-import withAuth from '../components/with-auth';
+import LoginRedirect from '../components/login-redirect';
+import auth0 from '../lib/auth0';
const Profile = ({ user }) => (
@@ -14,4 +16,4 @@ const Profile = ({ user }) => (
);
-export default withAuth(Profile);
+export default withAuth(Profile, LoginRedirect, auth0);
diff --git a/examples/basic-example/pages/protected-page.jsx b/examples/basic-example/pages/protected-page.jsx
index 9df18ab85..a11b76959 100644
--- a/examples/basic-example/pages/protected-page.jsx
+++ b/examples/basic-example/pages/protected-page.jsx
@@ -1,8 +1,9 @@
import React from 'react';
-import { useUser } from '@auth0/nextjs-auth0';
+import { useUser, withAuth } from '@auth0/nextjs-auth0';
import Layout from '../components/layout';
-import withAuth from '../components/with-auth';
+import LoginRedirect from '../components/login-redirect';
+import auth0 from '../lib/auth0';
export function ProtectedPage() {
const { user, loading } = useUser();
@@ -23,4 +24,4 @@ export function ProtectedPage() {
);
}
-export default withAuth(ProtectedPage);
+export default withAuth(ProtectedPage, LoginRedirect, auth0);
diff --git a/examples/typescript-example/components/layout.tsx b/examples/typescript-example/components/layout.tsx
index a0ee016b0..928cc1421 100644
--- a/examples/typescript-example/components/layout.tsx
+++ b/examples/typescript-example/components/layout.tsx
@@ -3,7 +3,7 @@ import Head from 'next/head';
import Header from './header';
-type LayoutProps = React.PropsWithChildren;
+type LayoutProps = React.PropsWithChildren<{}>;
const Layout: React.FunctionComponent = ({ children }: LayoutProps) => (
<>
diff --git a/examples/typescript-example/components/login-redirect.tsx b/examples/typescript-example/components/login-redirect.tsx
index f3f785834..e85f56343 100644
--- a/examples/typescript-example/components/login-redirect.tsx
+++ b/examples/typescript-example/components/login-redirect.tsx
@@ -1,19 +1,11 @@
-import Router from 'next/router';
-import React, { Component } from 'react';
+import React from 'react';
-import Layout from '../components/layout';
-import createLoginUrl from '../lib/url-helper';
+import Layout from './layout';
-export default class RedirectToLogin extends Component {
- componentDidMount(): void {
- window.location.assign(createLoginUrl(Router.pathname));
- }
+const LoginRedirect = (): React.ReactElement => (
+
+ Signing you in...
+
+);
- render(): React.ReactElement {
- return (
-
- Signing you in...
-
- );
- }
-}
+export default LoginRedirect;
diff --git a/examples/typescript-example/components/with-auth.tsx b/examples/typescript-example/components/with-auth.tsx
deleted file mode 100644
index 12e645631..000000000
--- a/examples/typescript-example/components/with-auth.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-import React from 'react';
-import { NextPage, NextPageContext } from 'next';
-import { UserProfile, useUser } from '@auth0/nextjs-auth0';
-
-import auth0 from '../lib/auth0';
-import createLoginUrl from '../lib/url-helper';
-import RedirectToLogin from '../components/login-redirect';
-
-type AuthenticatedProps = React.PropsWithChildren<{ user?: UserProfile }>;
-
-export default function withAuth(
- InnerComponent: React.ElementType | React.FunctionComponent
-): NextPage {
- const Authenticated: NextPage = (props) => {
- const { user } = useUser();
-
- if (!user) {
- return ; // do you need a "redirecting to login" route?
- }
-
- return ;
- };
-
- Authenticated.getInitialProps = async (context: NextPageContext): Promise => {
- if (!context.req) {
- const response = await fetch('/api/me');
- const result = response.ok ? await response.json() : null;
-
- return { user: result, children: undefined };
- }
-
- const session = await auth0.getSession(context.req, context.res);
-
- if (!session || !session.user) {
- context.res.writeHead(302, {
- Location: createLoginUrl(context.req.url)
- });
- context.res.end();
-
- return;
- }
-
- return { user: session.user, children: undefined };
- };
-
- return Authenticated;
-}
diff --git a/examples/typescript-example/lib/url-helper.ts b/examples/typescript-example/lib/url-helper.ts
deleted file mode 100644
index a2b294b78..000000000
--- a/examples/typescript-example/lib/url-helper.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-export default function createLoginUrl(redirectTo?: string): string {
- if (redirectTo) {
- return `/api/login?redirectTo=${encodeURIComponent(redirectTo)}`;
- }
- return `/api/login`;
-}
diff --git a/examples/typescript-example/pages/profile-ssr.tsx b/examples/typescript-example/pages/profile-ssr.tsx
index 5ac9e9c4b..b6d7af33b 100644
--- a/examples/typescript-example/pages/profile-ssr.tsx
+++ b/examples/typescript-example/pages/profile-ssr.tsx
@@ -1,8 +1,9 @@
import React from 'react';
-import { UserProfile } from '@auth0/nextjs-auth0';
+import { UserProfile, withAuth } from '@auth0/nextjs-auth0';
import Layout from '../components/layout';
-import withAuth from '../components/with-auth';
+import LoginRedirect from '../components/login-redirect';
+import auth0 from '../lib/auth0';
type ProfileProps = { user: UserProfile };
@@ -17,4 +18,4 @@ const Profile = ({ user }: ProfileProps): React.ReactElement => (
);
-export default withAuth(Profile);
+export default withAuth(Profile, LoginRedirect, auth0);
diff --git a/examples/typescript-example/pages/protected-page.tsx b/examples/typescript-example/pages/protected-page.tsx
index 209cf2cbd..1787d03d3 100644
--- a/examples/typescript-example/pages/protected-page.tsx
+++ b/examples/typescript-example/pages/protected-page.tsx
@@ -1,8 +1,9 @@
import React from 'react';
-import { useUser } from '@auth0/nextjs-auth0';
+import { useUser, withAuth } from '@auth0/nextjs-auth0';
import Layout from '../components/layout';
-import withAuth from '../components/with-auth';
+import LoginRedirect from '../components/login-redirect';
+import auth0 from '../lib/auth0';
export function ProtectedPage(): React.ReactElement {
const { user, loading } = useUser();
@@ -23,4 +24,4 @@ export function ProtectedPage(): React.ReactElement {
);
}
-export default withAuth(ProtectedPage);
+export default withAuth(ProtectedPage, LoginRedirect, auth0);
diff --git a/src/handlers/login.ts b/src/handlers/login.ts
index 928ecee23..bf69fc78e 100644
--- a/src/handlers/login.ts
+++ b/src/handlers/login.ts
@@ -1,6 +1,6 @@
import { NextApiResponse, NextApiRequest } from 'next';
import { ClientFactory, Config, loginHandler as getLoginHandler, LoginOptions } from '../auth0-session';
-import isSafeRedirect from '../utils/url-helpers';
+import { isSafeRedirect } from '../utils/url-helpers';
import TransientCookieHandler from '../auth0-session/transient-handler';
export default function loginHandler(
diff --git a/src/hooks/index.ts b/src/hooks/index.ts
new file mode 100644
index 000000000..f89de3621
--- /dev/null
+++ b/src/hooks/index.ts
@@ -0,0 +1,2 @@
+export { default as UserProvider, UserProfile, UserContext, useUser } from './use-user';
+export { default as withAuth } from './with-auth';
diff --git a/src/hooks/use-user.tsx b/src/hooks/use-user.tsx
index d932fb7f6..3de40817f 100644
--- a/src/hooks/use-user.tsx
+++ b/src/hooks/use-user.tsx
@@ -11,23 +11,25 @@ export interface UserProfile {
[key: string]: unknown; // Any custom claim which could be in the profile
}
+export type NullableUserProfile = UserProfile | null;
+
export interface UserContext {
- user: UserProfile | null;
+ user: NullableUserProfile;
loading: boolean;
}
-type UserProviderProps = React.PropsWithChildren<{ user: UserProfile | null }>;
-
const User = createContext({ user: null, loading: false });
export const useUser = (): UserContext => useContext(User);
+type UserProviderProps = React.PropsWithChildren<{ user: NullableUserProfile }>;
+
export default ({ children, user: initialUser }: UserProviderProps): ReactElement => {
- const [user, setUser] = useState(() => initialUser); // if used withAuth, initialUser is populated
+ const [user, setUser] = useState(() => initialUser); // with withAuth, initialUser gets populated
const [loading, setLoading] = useState(() => !initialUser); // if initialUser is populated, no loading needed
useEffect((): void => {
- if (user) return; // if initialUser is populated, no loading required
+ if (user) return; // if initialUser is populated, no loading needed
(async (): Promise => {
const response = await fetch('/api/me');
diff --git a/src/hooks/with-auth.tsx b/src/hooks/with-auth.tsx
new file mode 100644
index 000000000..19d544d84
--- /dev/null
+++ b/src/hooks/with-auth.tsx
@@ -0,0 +1,63 @@
+import React, { Component } from 'react';
+import { NextApiRequest, NextApiResponse, NextPage, NextPageContext } from 'next';
+import Router from 'next/router';
+
+import { NullableUserProfile, useUser } from './use-user';
+import { ISignInWithAuth0 } from '../instance';
+import { createLoginUrl } from '../utils/url-helpers';
+
+type RedirectToLoginProps = {
+ render: () => React.ReactElement;
+};
+
+class RedirectToLogin extends Component {
+ public componentDidMount(): void {
+ window.location.assign(createLoginUrl(Router.pathname));
+ }
+
+ public render(): React.ReactElement {
+ return this.props.render();
+ }
+}
+
+type AuthenticatedProps = React.PropsWithChildren<{ user: NullableUserProfile }>;
+
+export default function withAuth(
+ InnerComponent: React.ElementType,
+ redirect: () => React.ReactElement,
+ instance: ISignInWithAuth0
+): NextPage {
+ const Authenticated: NextPage = (props) => {
+ const { user } = useUser();
+
+ if (!user) {
+ return ;
+ }
+
+ return ;
+ };
+
+ Authenticated.getInitialProps = async (context: NextPageContext): Promise => {
+ if (!context.req) {
+ const response = await fetch('/api/me');
+ const result = response.ok ? await response.json() : null;
+
+ return { user: result };
+ }
+
+ const session = await instance.getSession(context.req as NextApiRequest, context.res as NextApiResponse);
+
+ if (!session || !session.user) {
+ context.res?.writeHead(302, {
+ Location: createLoginUrl(context.req.url)
+ });
+ context.res?.end();
+
+ return { user: null };
+ }
+
+ return { user: session.user as NullableUserProfile };
+ };
+
+ return Authenticated;
+}
diff --git a/src/index.browser.ts b/src/index.browser.ts
index 13e3d716d..2f6d3a3c6 100644
--- a/src/index.browser.ts
+++ b/src/index.browser.ts
@@ -3,7 +3,7 @@ import { ConfigParameters } from './auth0-session';
import Instance from './instance.browser';
import { ISignInWithAuth0 } from './instance';
-export { default as UserProvider, UserProfile, UserContext, useUser } from './hooks/use-user';
+export { UserProvider, UserProfile, UserContext, useUser, withAuth } from './hooks';
// @ts-ignore un-used settings
export function initAuth0(config: ConfigParameters): ISignInWithAuth0 {
diff --git a/src/index.ts b/src/index.ts
index 670439466..8969ceed9 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -2,7 +2,7 @@
import { ConfigParameters } from './auth0-session';
import { ISignInWithAuth0 } from './instance';
-export { default as UserProvider, UserProfile, UserContext, useUser } from './hooks/use-user';
+export { UserProvider, UserProfile, UserContext, useUser, withAuth } from './hooks';
export function initAuth0(settings: ConfigParameters): ISignInWithAuth0 {
const isBrowser = typeof window !== 'undefined' || (process as any).browser;
diff --git a/src/utils/url-helpers.ts b/src/utils/url-helpers.ts
index ac0fbcf65..3cf497daf 100644
--- a/src/utils/url-helpers.ts
+++ b/src/utils/url-helpers.ts
@@ -2,7 +2,7 @@
* Helper which tests if a URL can safely be redirected to. Requires the URL to be relative.
* @param url
*/
-export default function isSafeRedirect(url: string): boolean {
+export function isSafeRedirect(url: string): boolean {
if (typeof url !== 'string') {
throw new TypeError(`Invalid url: ${url}`);
}
@@ -14,3 +14,15 @@ export default function isSafeRedirect(url: string): boolean {
return !/^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(url);
}
+
+/**
+ * Helper which creates the login URL to redirect to.
+ * @param redirectTo
+ */
+export function createLoginUrl(redirectTo?: string): string {
+ if (redirectTo) {
+ return `/api/login?redirectTo=${encodeURIComponent(redirectTo)}`;
+ }
+
+ return `/api/login`;
+}
diff --git a/tests/helpers/hooks.tsx b/tests/helpers/hooks.tsx
index cf793b5fb..5c3fdfb4d 100644
--- a/tests/helpers/hooks.tsx
+++ b/tests/helpers/hooks.tsx
@@ -17,7 +17,7 @@ export const user: UserProfile = {
};
export const withUser = (user: UserProfile | null) => {
- return ({ children }: React.PropsWithChildren): React.ReactElement => (
+ return ({ children }: React.PropsWithChildren<{}>): React.ReactElement => (
{children}
);
};