Skip to content

Commit

Permalink
[core] Add passkey provider support and example (#4063)
Browse files Browse the repository at this point in the history
  • Loading branch information
bharatkashyap authored Oct 18, 2024
1 parent 45d2188 commit 0610dcf
Show file tree
Hide file tree
Showing 32 changed files with 830 additions and 115 deletions.
20 changes: 14 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,31 +40,39 @@ yarn-error.log*
.sentryclirc

# docs

/docs/export

# lerna

lerna-debug.log

# env

.env

# build output

dist/
build/

# studio
packages/toolpad-studio/public/web_modules
packages/toolpad-studio/public/runtime
packages/toolpad-studio/public/typings.json
.toolpad-generated

# examples
examples/*/yarn.lock

test-results
.toolpad-generated

.yarn-playwright-cache
# tests

test-results
.yarn-playwright-cache
/test/regressions/screenshots/**
.coverage

# vale downloaded config
.github/styles/Google
.github/styles/MUI
.github/styles/.vale-config

.coverage
45 changes: 0 additions & 45 deletions docs/data/toolpad/core/components/sign-in-page/AuthJsSignInApp.js

This file was deleted.

49 changes: 0 additions & 49 deletions docs/data/toolpad/core/components/sign-in-page/AuthJsSignInApp.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import * as React from 'react';
import { AppProvider } from '@toolpad/core/AppProvider';
import { SignInPage } from '@toolpad/core/SignInPage';
import { useTheme } from '@mui/material/styles';
// preview-start
const providers = [{ id: 'passkey', name: 'Passkey' }];
// preview-end

const signIn = async (provider) => {
const promise = new Promise((resolve) => {
setTimeout(() => {
alert(`Signing in with ${provider.id}`);
resolve();
}, 500);
});
return promise;
};

export default function PasskeySignInPage() {
const theme = useTheme();
return (
// preview-start
<AppProvider theme={theme}>
<SignInPage signIn={signIn} providers={providers} />
</AppProvider>
// preview-end
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import * as React from 'react';
import { AppProvider } from '@toolpad/core/AppProvider';
import { SignInPage, AuthProvider } from '@toolpad/core/SignInPage';
import { useTheme } from '@mui/material/styles';
// preview-start
const providers = [{ id: 'passkey', name: 'Passkey' }];
// preview-end

const signIn: (provider: AuthProvider) => void = async (provider) => {
const promise = new Promise<void>((resolve) => {
setTimeout(() => {
alert(`Signing in with ${provider.id}`);
resolve();
}, 500);
});
return promise;
};

export default function PasskeySignInPage() {
const theme = useTheme();
return (
// preview-start
<AppProvider theme={theme}>
<SignInPage signIn={signIn} providers={providers} />
</AppProvider>
// preview-end
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const providers = [{ id: 'passkey', name: 'Passkey' }];

// ...

<AppProvider theme={theme}>
<SignInPage signIn={signIn} providers={providers} />
</AppProvider>
14 changes: 13 additions & 1 deletion docs/data/toolpad/core/components/sign-in-page/sign-in-page.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,22 @@ The following providers are supported and maintained by default:
Find details on how to set up each provider in the [Auth.js documentation](https://authjs.dev/getting-started/authentication/oauth).
:::

## Passkey

The `SignInPage` component can be set up to use [Passkeys](https://passkeys.dev) by passing in a provider with `passkey` as the `id`:

{{"demo": "PasskeySignInPage.js", "iframe": true}}

:::info
The [Toolpad Core Passkey example app](https://github.com/mui/mui-toolpad/tree/master/examples/core-auth-nextjs-passkey/) comes with a working app using `next-auth/webauthn`, Prisma and PostgreSQL.
:::

{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/docs/core/auth-next-passkey.png", "srcDark": "/static/toolpad/docs/core/auth-next-passkey-dark.png", "alt": "Auth.js Passkeys & Next.js with Toolpad Core sign-in page", "caption": "Auth.js Passkeys & Next.js app router with Toolpad Core Sign-in page", "zoom": true, "aspectRatio": "1.428" }}

## Credentials

:::warning
It is recommended to use the OAuth provider for more robust maintenance, support, and security.
It is recommended to use the OAuth or Passkey provider for more robust maintenance, support, and security.
:::

To render a username password form, pass in a provider with `credentials` as the `id` property. The `signIn` function accepts a `formData` parameter in this case.
Expand Down
2 changes: 1 addition & 1 deletion docs/pages/toolpad/core/api/sign-in-page.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"providers": {
"type": {
"name": "arrayOf",
"description": "Array&lt;{ id: 'apple'<br>&#124;&nbsp;'auth0'<br>&#124;&nbsp;'cognito'<br>&#124;&nbsp;'credentials'<br>&#124;&nbsp;'discord'<br>&#124;&nbsp;'facebook'<br>&#124;&nbsp;'fusionauth'<br>&#124;&nbsp;'github'<br>&#124;&nbsp;'gitlab'<br>&#124;&nbsp;'google'<br>&#124;&nbsp;'instagram'<br>&#124;&nbsp;'keycloak'<br>&#124;&nbsp;'line'<br>&#124;&nbsp;'linkedin'<br>&#124;&nbsp;'microsoft-entra-id'<br>&#124;&nbsp;'okta'<br>&#124;&nbsp;'slack'<br>&#124;&nbsp;'spotify'<br>&#124;&nbsp;'tiktok'<br>&#124;&nbsp;'twitch'<br>&#124;&nbsp;'twitter', name: string }&gt;"
"description": "Array&lt;{ id: 'apple'<br>&#124;&nbsp;'auth0'<br>&#124;&nbsp;'cognito'<br>&#124;&nbsp;'credentials'<br>&#124;&nbsp;'discord'<br>&#124;&nbsp;'facebook'<br>&#124;&nbsp;'fusionauth'<br>&#124;&nbsp;'github'<br>&#124;&nbsp;'gitlab'<br>&#124;&nbsp;'google'<br>&#124;&nbsp;'instagram'<br>&#124;&nbsp;'keycloak'<br>&#124;&nbsp;'line'<br>&#124;&nbsp;'linkedin'<br>&#124;&nbsp;'microsoft-entra-id'<br>&#124;&nbsp;'okta'<br>&#124;&nbsp;'passkey'<br>&#124;&nbsp;'slack'<br>&#124;&nbsp;'spotify'<br>&#124;&nbsp;'tiktok'<br>&#124;&nbsp;'twitch'<br>&#124;&nbsp;'twitter', name: string }&gt;"
},
"default": "[]"
},
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions examples/core-auth-nextjs-passkey/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "next/core-web-vitals"
}
5 changes: 5 additions & 0 deletions examples/core-auth-nextjs-passkey/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules/
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
50 changes: 50 additions & 0 deletions examples/core-auth-nextjs-passkey/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Toolpad Core Playground - Next.js App Router with Passkey

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

1. You need to have a Postgres database running. You can use the following docker command to start a Postgres database:

```bash
docker run --name postgres -e POSTGRES_PASSWORD=postgres -p 5432:5432 -d postgres
```

2. For the database created above, the connection string is `postgresql://postgres:postgres@localhost:5432/postgres`.

3. Update the `DATABASE_URL` environment variable in the `.env` file with the connection string for the database you created above.

4. Then, generate the Prisma Client:

```bash
npx prisma generate --schema=./src/prisma/schema.prisma
```

5. Finally, run the development server:

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

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

## 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 the [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
5 changes: 5 additions & 0 deletions examples/core-auth-nextjs-passkey/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.
4 changes: 4 additions & 0 deletions examples/core-auth-nextjs-passkey/next.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/** @type {import('next').NextConfig} */
const nextConfig = {};

export default nextConfig;
32 changes: 32 additions & 0 deletions examples/core-auth-nextjs-passkey/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"name": "core-auth-nextjs-passkey",
"version": "0.1.0",
"scripts": {
"dev": "next dev",
"lint": "next lint"
},
"dependencies": {
"@auth/prisma-adapter": "2.4.2",
"@emotion/react": "11.13.3",
"@emotion/styled": "11.13.0",
"@mui/icons-material": "6.0.2",
"@mui/lab": "6.0.0-beta.9",
"@mui/material": "6.0.2",
"@mui/material-nextjs": "6.0.2",
"@prisma/client": "5.19.1",
"@simplewebauthn/browser": "9.0.1",
"@simplewebauthn/server": "9.0.3",
"@toolpad/core": "workspace:*",
"next": "14.2.7",
"next-auth": "5.0.0-beta.20",
"react": "18.3.1",
"react-dom": "18.3.1"
},
"devDependencies": {
"@types/node": "22.5.1",
"@types/react": "18.3.5",
"@types/react-dom": "18.3.0",
"eslint-config-next": "14.2.7",
"prisma": "5.19.1"
}
}
11 changes: 11 additions & 0 deletions examples/core-auth-nextjs-passkey/src/app/(dashboard)/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import * as React from 'react';
import { DashboardLayout } from '@toolpad/core/DashboardLayout';
import { PageContainer } from '@toolpad/core/PageContainer';

export default async function DashboardPagesLayout(props: { children: React.ReactNode }) {
return (
<DashboardLayout>
<PageContainer>{props.children}</PageContainer>
</DashboardLayout>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import * as React from 'react';
import Typography from '@mui/material/Typography';
import Box from '@mui/material/Box';
import { redirect } from 'next/navigation';
import { headers } from 'next/headers';
import { auth } from '../../../auth';

export default async function OrdersPage() {
const session = await auth();
const currentUrl = headers().get('referer') || 'http://localhost:3000';

if (!session) {
// Get the current URL to redirect to signIn with `callbackUrl`
const redirectUrl = new URL('/auth/signin', currentUrl);
redirectUrl.searchParams.set('callbackUrl', currentUrl);

redirect(redirectUrl.toString());
}
return (
<Box
sx={{
my: 4,
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
textAlign: 'center',
}}
>
<Typography sx={{ mb: 2 }}>Welcome to the Toolpad orders!</Typography>
</Box>
);
}
Loading

0 comments on commit 0610dcf

Please sign in to comment.