Skip to content

Commit

Permalink
♻️ Update example description
Browse files Browse the repository at this point in the history
  • Loading branch information
cermakjiri committed Oct 31, 2024
1 parent 4a45c22 commit f2cda3d
Show file tree
Hide file tree
Showing 10 changed files with 79 additions and 61 deletions.
2 changes: 1 addition & 1 deletion examples/simplewebauthn/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Passkeys with SimpleWebAuthn & Firebase

- Creating (user registration), retrieving (user login), linking, removing of passkeys.
- Creating (user registration), retrieving (user login), linking multiple, and removing passkeys.
- Issuing a JWT token via Firebase Auth once user is authenticated.
- Passkes are stored in Firebase Firestore.
- Formatting and parsing of WebAuthn API request / responses done via SimpleWebAuthn library.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,11 @@ export const LoginWithPasskey = () => {
>
<FieldsStack>
<FormError />
<EmailField<LoginFormValues> name='email' autoComplete='username webauthn' />
<EmailField<LoginFormValues>
name='email'
autoComplete='username webauthn'
label='Email (optional)'
/>
</FieldsStack>

<SubmitButton sx={{ mt: 3 }} endIcon={<Fingerprint />}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ export const Passkeys = () => {
const postRemovalDialog = useDialog<PostRemovalDialogProps['data']>();
const removePasskey = useRemovePasskey(postRemovalDialog.openDialog);

// TODO: How to detect if given passkey has been removed from a authenticator (e.g. removed from Apple keychain)?

return (
<>
<PasskeysHeader>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { Container, ExampleHeader } from '@workspace/ui';
import Link from 'next/link';

import { Container, ExampleDescription, ExampleHeader } from '@workspace/ui';

import { MainHeader } from '~modules/layout/components';

Expand All @@ -8,64 +10,33 @@ import { ExampleWrapper } from './PasskeysWithFirebasePage.styles';
export const PasskeysWithFirebasePage = () => {
return (
<>
<MainHeader pageTitle='Passkeys Authentication with Firebase' />
<MainHeader pageTitle='Passkeys authentication' />

<ExampleWrapper>
<Container maxWidth='lg'>
<ExampleHeader
title='Passkeys authentication with Firebase'
title='Authenticate with passkeys'
description={
<>
A full-stack example of creating a passkey (attestation ceremony) and then retrieving it
(assertation ceremony) with Firebase Firestore integration to store the passkey and
Firebase Auth for issuing a JWT token.
</>
<ExampleDescription
description='This demo showcases the use of WebAuthn API:'
features={[
'Creating (user registration), retrieving (user login), linking multiple, and removing passkeys.',
<>
Formatting and parsing of WebAuthn API requests / responses with{' '}
<Link href='https://simplewebauthn.dev' target='_blank'>
SimpleWebAuthn
</Link>
.
</>,
'Issuing a JWT token via Firebase Auth once user is authenticated.',
'Passkes are stored in Firebase Firestore.',
]}
/>
}
/>

<FirebaseExample />

{/* <Words variant='body2' sx={{ mt: 6 }}>
TODO: example stack - list of badges (and tooltips) TODO: complete diagrams for registration and
login ceremonies
</Words> */}
</Container>
</ExampleWrapper>

{/* <FeaturesContainer maxWidth='lg'>
<Features
featuresWithCategory={[
{
icon: <Add />,
name: 'Pros',
features: [
{
label: 'Feature 1',
description: 'The passkey is stored in Firebase Firestore database.',
},
{
label: 'Feature 2',
description: 'The email is used as passkey username.',
},
],
},
{
icon: <Remove />,
name: 'Cons',
features: [
{
label: 'Feature 1',
description: 'Description 1 of the feature 1 of the pros section',
},
{
label: 'Feature 2',
description: 'Description 1 of the feature 1 of the pros section',
},
],
},
]}
/>
</FeaturesContainer> */}
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
* We might not want to provide list of available passkeys to unauthenticated users for privacy reasons:
* - https://w3c.github.io/webauthn/#sctn-credential-id-privacy-leak
* - https://w3c.github.io/webauthn/#sctn-unprotected-account-detection (This is not relevent for this demo but, I believe, developers should be aware of this when implementing WebAuthn in production.)
* // TODO: implement protection against privacy leaks above
*/
allowCredentials: passkeys.map(({ credentialId, transports }) => ({
id: credentialId,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { styled } from '@mui/material';

import { Words } from '../Words';

export const Features = styled('ul')(({ theme }) => ({
display: 'grid',
gridTemplateColumns: '1fr',
rowGap: theme.spacing(1),
listStyle: 'inside',
padding: 0,
margin: 0,
}));

export const Feature = styled(Words)(({ theme }) => ({
textWrap: 'balance',
lineHeight: 1.65,
}));
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { ReactNode } from 'react';

import { Words } from '../Words';
import { Feature, Features } from './ExampleDescription.styles';

export interface ExampleDescriptionProps {
description: ReactNode;
features?: ReactNode[];
}

export const ExampleDescription = ({ description, features = [] }: ExampleDescriptionProps) => {
return (
<>
<Words variant='body2' mb={features.length === 0 ? 0 : 1.25}>
{description}
</Words>

{features.length > 0 && (
<Features>
{features.map((features, index) => (
<Feature key={index} variant='body2' component='li'>
{features}
</Feature>
))}
</Features>
)}
</>
);
};
1 change: 1 addition & 0 deletions packages/ui/src/components/ExampleDescription/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './ExampleDescription';
12 changes: 5 additions & 7 deletions packages/ui/src/components/ExampleHeader/ExampleHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { ReactNode } from 'react';
import { Box } from '@mui/material';

import { Words } from '../Words';

Expand All @@ -10,20 +11,17 @@ export interface ExampleHeaderProps {
export const ExampleHeader = ({ title, description }: ExampleHeaderProps) => {
return (
<>
<Words variant='h2' sx={{ fontWeight: 'bold' }}>
<Words variant='h2' sx={{ fontWeight: 'bold', marginBottom: 2 }}>
{title}
</Words>
<Words
variant='body2'
<Box
mt={1}
sx={{
maxWidth: '600px',
textWrap: 'balance',
lineHeight: '1.65',
maxWidth: '800px',
}}
>
{description}
</Words>
</Box>
</>
);
};
1 change: 1 addition & 0 deletions packages/ui/src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from './Button';
export * from './Card';
export * from './Code';
export * from './ExampleDescription';
export * from './ExampleFrame';
export * from './ExampleHeader';
export * from './ExternalLink';
Expand Down

0 comments on commit f2cda3d

Please sign in to comment.