Skip to content

Commit

Permalink
feat: add support for passkeys (#63)
Browse files Browse the repository at this point in the history
  • Loading branch information
hperl committed Jan 10, 2024
1 parent 76060e7 commit b42fd65
Show file tree
Hide file tree
Showing 9 changed files with 73 additions and 9 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,6 @@ yarn-error.log*
dist/

cypress/videos
cypress/screenshots
cypress/screenshots

.idea
8 changes: 8 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion next-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
/// <reference types="next" />
/// <reference types="next/types/global" />
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
Expand Down
4 changes: 4 additions & 0 deletions pages/registration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ const Registration: NextPage = () => {
returnTo: returnTo ? String(returnTo) : undefined,
})
.then(({ data }) => {
console.log("Created a new registration flow: ", data)
setFlow(data)
})
.catch(handleFlowError(router, "registration", setFlow))
Expand All @@ -59,12 +60,15 @@ const Registration: NextPage = () => {
// his data when she/he reloads the page.
.push(`/registration?flow=${flow?.id}`, undefined, { shallow: true })

console.log("updateRegistrationFlow values", values)
ory
.updateRegistrationFlow({
flow: String(flow?.id),
updateRegistrationFlowBody: values,
})
.then(async ({ data }) => {
console.log("updateRegistrationFlow data", data)

// If we ended up here, it means we are successfully signed up!
//
// You can do cool stuff here, like having access to the identity which just signed up:
Expand Down
10 changes: 10 additions & 0 deletions pages/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,16 @@ const Settings: NextPage = () => {
flow={flow}
/>
</SettingsCard>
<SettingsCard only="webauthn" flow={flow}>
<H3>Manage Passkeys</H3>
<Messages messages={flow?.ui.messages} />
<Flow
hideGlobalMessages
onSubmit={onSubmit}
only="passkey"
flow={flow}
/>
</SettingsCard>
<ActionCard wide>
<Link href="/" passHref>
<CenterLink>Go back</CenterLink>
Expand Down
6 changes: 5 additions & 1 deletion pkg/ui/Flow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export type Methods =
| "profile"
| "totp"
| "webauthn"
| "passkey"
| "link"
| "lookup_secret"

Expand Down Expand Up @@ -155,8 +156,11 @@ export class Flow<T extends Values> extends Component<Props<T>, State<T>> {
isLoading: true,
}))

console.log("form data", body)
console.log("form data state values", this.state.values)

return this.props
.onSubmit({ ...body, ...this.state.values })
.onSubmit({ ...this.state.values, ...body })
.finally(() => {
// We wait for reconciliation and update the state after 50ms
// Done submitting - update loading status
Expand Down
9 changes: 6 additions & 3 deletions pkg/ui/NodeInputButton.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { getNodeLabel } from "@ory/integrations/ui"
import { Button } from "@ory/themes"
import { useEffect } from "react"

import { NodeInputProps } from "./helpers"
import { callWebauthnFunction, NodeInputProps, useOnload } from "./helpers"

export function NodeInputButton<T>({
node,
Expand All @@ -18,16 +19,18 @@ export function NodeInputButton<T>({
//
// Please note that we also need to prevent the default action from happening.
if (attributes.onclick) {
console.log("onclick", attributes.onclick)
e.stopPropagation()
e.preventDefault()
const run = new Function(attributes.onclick)
run()
callWebauthnFunction(attributes.onclick)
return
}

setValue(attributes.value).then(() => dispatchSubmit(e))
}

// useOnload(attributes as any)

return (
<>
<Button
Expand Down
13 changes: 11 additions & 2 deletions pkg/ui/NodeInputHidden.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
import { NodeInputProps } from "./helpers"
import { useEffect, useRef } from "react"

import { NodeInputProps, useOnload } from "./helpers"

export function NodeInputHidden<T>({ attributes }: NodeInputProps) {
// Render a hidden input field
const inputRef = useRef<HTMLInputElement>(null)

useOnload(attributes as any)

return (
<input
ref={inputRef}
type={attributes.type}
name={attributes.name}
value={attributes.value || "true"}
value={
inputRef.current ? inputRef.current?.value : attributes.value || "true"
}
/>
)
}
27 changes: 26 additions & 1 deletion pkg/ui/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { UiNode, UiNodeInputAttributes } from "@ory/client"
import { FormEvent, MouseEvent } from "react"
import { FormEvent, MouseEvent, useEffect } from "react"

export type ValueSetter = (
value: string | number | boolean | undefined,
Expand All @@ -17,3 +17,28 @@ export interface NodeInputProps {
dispatchSubmit: FormDispatcher
setValue: ValueSetter
}

export const useOnload = (attributes: { onload?: string }) => {
useEffect(() => {
if (attributes.onload) {
const intervalHandle = callWebauthnFunction(attributes.onload)

return () => {
window.clearInterval(intervalHandle)
}
}
}, [attributes])
}

export const callWebauthnFunction = (functionBody: string) => {
const run = new Function(functionBody)

const intervalHandle = window.setInterval(() => {
if ((window as any).__oryWebAuthnInitialized) {
run()
window.clearInterval(intervalHandle)
}
}, 100)

return intervalHandle
}

0 comments on commit b42fd65

Please sign in to comment.