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

[docs] Add next-auth v4 example #3982

Merged
merged 13 commits into from
Sep 3, 2024
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 54 additions & 28 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,60 @@ _If you're looking into contributing to the docs, follow the [instructions](#bui
- git
- node.js

### Developing on Toolpad Core

This uses the local version of Toolpad Core as built in the mono-repository, and allows for quickly testing out changes and their results.

Some application examples for different JavaScript frameworks (such as Next.js, Vite…) are present in the `playground` folder that can be used to quickly develop on Toolpad Core on a live application.

1. Install dependencies:

```bash
pnpm install
```

2. Run the built-in watch mode

```bash
pnpm dev
```

3. Run any application in the `playground` folder in development mode, such as `nextjs`

```bash
cd playground/nextjs
```

```bash
pnpm dev
```

### Testing the example apps

You can also test the example apps to make sure they work as expected.

1. Add the example app to the workspace

```yaml
packages:
- 'packages/*'
- 'docs'
- 'test'
- 'examples/nextjs'
```

2. Run Toolpad Core locally

```bash
pnpm --filter @toolpad/core dev
```

3. Run the example app

```bash
pnpm --filter core-nextjs dev
```

### Running Toolpad Studio apps inside the monorepo (recommended)

This uses the local version of Toolpad Studio as built in the mono-repository.
Expand Down Expand Up @@ -151,34 +205,6 @@ pnpm install

</details>

### Developing on Toolpad Core

This uses the local version of Toolpad Core as built in the mono-repository, and allows for quickly testing out changes and their results.

Some application examples for different JavaScript frameworks (such as Next.js, Vite…) are present in the `playground` folder that can be used to quickly develop on Toolpad Core on a live application.

1. Install dependencies:

```bash
pnpm install
```

2. Run the built-in watch mode

```bash
pnpm dev
```

3. Run any application in the `playground` folder in development mode, such as `nextjs`

```bash
cd playground/nextjs
```

```bash
pnpm dev
```

## Running integration tests

The playwright tests can be run in one of two modes:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,14 @@ export default function SignIn() {
}
```

:::success
If you're using the default [Next.js example](https://github.com/mui/mui-toolpad/tree/master/examples/core-auth-nextjs/), all of this is already configured for you. Otherwise, follow the [custom sign-in page instructions](https://authjs.dev/guides/pages/signin).
:::

:::info
If you're not on the Next Auth v5 version yet, see the [example with Next Auth v4](https://github.com/mui/mui-toolpad/tree/master/examples/core-auth-nextjs-pages-nextauth-4/) to get started.
:::

## Customization

### Branding
Expand Down
3 changes: 3 additions & 0 deletions examples/core-auth-nextjs-pages-nextauth-4/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "next/core-web-vitals"
}
34 changes: 34 additions & 0 deletions examples/core-auth-nextjs-pages-nextauth-4/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Toolpad Core Playground - Next.js Pages Router with Next Auth 4

This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).

## Getting Started

First, run the development server:

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

## Learn More

To learn more about Next.js, take a look at the following resources:

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!

## Deploy on Vercel

The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.

Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
5 changes: 5 additions & 0 deletions examples/core-auth-nextjs-pages-nextauth-4/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
6 changes: 6 additions & 0 deletions examples/core-auth-nextjs-pages-nextauth-4/next.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
};

export default nextConfig;
30 changes: 30 additions & 0 deletions examples/core-auth-nextjs-pages-nextauth-4/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "core-auth-nextjs-pages-nextauth-4",
"version": "0.1.0",
"scripts": {
"dev": "next dev",
"lint": "next lint"
},
"dependencies": {
"@emotion/react": "^11",
"@emotion/styled": "^11",
"@emotion/cache": "^11",
"@emotion/server": "^11",
"@mui/icons-material": "^6",
"@mui/material": "^6",
"@mui/material-nextjs": "^6",
"@toolpad/core": "latest",
"next": "^14",
"next-auth": "^4.24.7",
"react": "^18",
"react-dom": "^18"
},
"devDependencies": {
"typescript": "^5",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"eslint": "^8",
"eslint-config-next": "^14"
}
}
107 changes: 107 additions & 0 deletions examples/core-auth-nextjs-pages-nextauth-4/src/pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import * as React from 'react';
import { AppProvider } from '@toolpad/core/nextjs';
import { DashboardLayout } from '@toolpad/core/DashboardLayout';
import Head from 'next/head';
import { useRouter } from 'next/router';
import { AppCacheProvider } from '@mui/material-nextjs/v14-pagesRouter';
import DashboardIcon from '@mui/icons-material/Dashboard';
import ShoppingCartIcon from '@mui/icons-material/ShoppingCart';
import type { NextPage } from 'next';
import type { AppProps } from 'next/app';
import type { Navigation } from '@toolpad/core';
import { SessionProvider, signIn, signOut, useSession } from 'next-auth/react';
import LinearProgress from '@mui/material/LinearProgress';

export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
getLayout?: (page: React.ReactElement) => React.ReactNode;
requireAuth?: boolean;
};

type AppPropsWithLayout = AppProps & {
Component: NextPageWithLayout;
};

const NAVIGATION: Navigation = [
{
kind: 'header',
title: 'Main items',
},
{
title: 'Dashboard',
icon: <DashboardIcon />,
},
{
segment: 'orders',
title: 'Orders',
icon: <ShoppingCartIcon />,
},
];

const BRANDING = {
title: 'My Toolpad Core App',
};

const AUTHENTICATION = {
signIn,
signOut,
};

function getDefaultLayout(page: React.ReactElement) {
return <DashboardLayout>{page}</DashboardLayout>;
}

function RequireAuth({ children }: { children: React.ReactNode }) {
const { status } = useSession();
const router = useRouter();

if (status === 'loading') {
return <LinearProgress />;
}

if (status === 'unauthenticated') {
router.push('/auth/signin');
}

return children;
}

function AppLayout({ children }: { children: React.ReactNode }) {
const { data: session } = useSession();
return (
<React.Fragment>
<Head>
<meta name="viewport" content="initial-scale=1, width=device-width" />
</Head>
<AppProvider
navigation={NAVIGATION}
branding={BRANDING}
session={session}
authentication={AUTHENTICATION}
>
{children}
</AppProvider>
</React.Fragment>
);
}

export default function App(props: AppPropsWithLayout) {
const {
Component,
pageProps: { session, ...pageProps },
} = props;

const getLayout = Component.getLayout ?? getDefaultLayout;
const requireAuth = Component.requireAuth ?? true;

let pageContent = getLayout(<Component {...pageProps} />);
if (requireAuth) {
pageContent = <RequireAuth>{pageContent}</RequireAuth>;
}
pageContent = <AppLayout>{pageContent}</AppLayout>;

return (
<AppCacheProvider {...props}>
<SessionProvider session={session}>{pageContent}</SessionProvider>
</AppCacheProvider>
);
}
27 changes: 27 additions & 0 deletions examples/core-auth-nextjs-pages-nextauth-4/src/pages/_document.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import * as React from 'react';
import { Html, Head, Main, NextScript, DocumentProps, DocumentContext } from 'next/document';
import {
DocumentHeadTags,
DocumentHeadTagsProps,
documentGetInitialProps,
} from '@mui/material-nextjs/v14-pagesRouter';

export default function Document(props: DocumentProps & DocumentHeadTagsProps) {
return (
<Html lang="en" data-toolpad-color-scheme="light">
<Head>
<meta name="emotion-insertion-point" content="" />
<DocumentHeadTags {...props} />
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}

Document.getInitialProps = async (ctx: DocumentContext) => {
const finalProps = await documentGetInitialProps(ctx);
return finalProps;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import NextAuth from 'next-auth';
import GithubProvider from 'next-auth/providers/github';
import CredentialsProvider from 'next-auth/providers/credentials';

export const authOptions = {
providers: [
GithubProvider({
clientId: process.env.GITHUB_CLIENT_ID ?? '',
clientSecret: process.env.GITHUB_CLIENT_SECRET ?? '',
}),
CredentialsProvider({
// The name to display on the sign in form (e.g. 'Sign in with...')
credentials: {
email: { label: 'Email Address', type: 'email' },
password: { label: 'Password', type: 'password' },
},
async authorize(credentials) {
if (credentials?.password !== 'password') {
return null;
}
return {
id: 'test',
name: 'Test User',
email: String(credentials?.email),
};
},
}),
],
secret: process.env.AUTH_SECRET,
pages: {
signIn: '/auth/signin',
},
};

export default NextAuth(authOptions);
Loading
Loading