@delmaredigital/payload-better-auth 0.3.8 → 0.3.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapter/collections.d.ts +0 -1
- package/dist/adapter/collections.js +0 -2
- package/dist/adapter/index.d.ts +0 -1
- package/dist/adapter/index.js +0 -2
- package/dist/components/BeforeLogin.d.ts +0 -1
- package/dist/components/BeforeLogin.js +0 -2
- package/dist/components/LoginView.d.ts +0 -1
- package/dist/components/LoginView.js +0 -2
- package/dist/components/LoginViewWrapper.d.ts +0 -1
- package/dist/components/LoginViewWrapper.js +0 -2
- package/dist/components/LogoutButton.d.ts +0 -1
- package/dist/components/LogoutButton.js +0 -2
- package/dist/components/PasskeyRegisterButton.d.ts +0 -1
- package/dist/components/PasskeyRegisterButton.js +0 -2
- package/dist/components/PasskeySignInButton.d.ts +0 -1
- package/dist/components/PasskeySignInButton.js +0 -2
- package/dist/components/auth/ForgotPasswordView.d.ts +0 -1
- package/dist/components/auth/ForgotPasswordView.js +0 -2
- package/dist/components/auth/ResetPasswordView.d.ts +0 -1
- package/dist/components/auth/ResetPasswordView.js +0 -2
- package/dist/components/auth/index.d.ts +0 -1
- package/dist/components/auth/index.js +0 -2
- package/dist/components/management/ApiKeysManagementClient.d.ts +0 -1
- package/dist/components/management/ApiKeysManagementClient.js +0 -2
- package/dist/components/management/PasskeysManagementClient.d.ts +0 -1
- package/dist/components/management/PasskeysManagementClient.js +0 -2
- package/dist/components/management/SecurityNavLinks.d.ts +0 -1
- package/dist/components/management/SecurityNavLinks.js +0 -2
- package/dist/components/management/TwoFactorManagementClient.d.ts +0 -1
- package/dist/components/management/TwoFactorManagementClient.js +0 -2
- package/dist/components/management/index.d.ts +0 -1
- package/dist/components/management/index.js +0 -2
- package/dist/components/management/views/ApiKeysView.d.ts +0 -1
- package/dist/components/management/views/ApiKeysView.js +0 -2
- package/dist/components/management/views/PasskeysView.d.ts +0 -1
- package/dist/components/management/views/PasskeysView.js +0 -2
- package/dist/components/management/views/TwoFactorView.d.ts +0 -1
- package/dist/components/management/views/TwoFactorView.js +0 -2
- package/dist/components/management/views/index.d.ts +0 -1
- package/dist/components/management/views/index.js +0 -2
- package/dist/components/twoFactor/TwoFactorSetupView.d.ts +0 -1
- package/dist/components/twoFactor/TwoFactorSetupView.js +0 -2
- package/dist/components/twoFactor/TwoFactorVerifyView.d.ts +0 -1
- package/dist/components/twoFactor/TwoFactorVerifyView.js +0 -2
- package/dist/components/twoFactor/index.d.ts +0 -1
- package/dist/components/twoFactor/index.js +0 -2
- package/dist/exports/client.d.ts +0 -1
- package/dist/exports/client.js +0 -2
- package/dist/exports/components.d.ts +0 -1
- package/dist/exports/components.js +0 -2
- package/dist/exports/management.d.ts +0 -1
- package/dist/exports/management.js +0 -2
- package/dist/exports/rsc.d.ts +0 -1
- package/dist/exports/rsc.js +0 -2
- package/dist/generated-types.d.ts +0 -1
- package/dist/generated-types.js +0 -2
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -2
- package/dist/plugin/index.d.ts +0 -1
- package/dist/plugin/index.js +0 -2
- package/dist/scripts/generate-types.d.ts +0 -1
- package/dist/scripts/generate-types.js +0 -2
- package/dist/types/apiKey.d.ts +0 -1
- package/dist/types/apiKey.js +0 -2
- package/dist/types/betterAuth.d.ts +0 -1
- package/dist/types/betterAuth.js +0 -2
- package/dist/utils/access.d.ts +0 -1
- package/dist/utils/access.js +0 -2
- package/dist/utils/apiKeyAccess.d.ts +0 -1
- package/dist/utils/apiKeyAccess.js +0 -2
- package/dist/utils/betterAuthDefaults.d.ts +0 -1
- package/dist/utils/betterAuthDefaults.js +0 -2
- package/dist/utils/detectAuthConfig.d.ts +0 -1
- package/dist/utils/detectAuthConfig.js +0 -2
- package/dist/utils/detectEnabledPlugins.d.ts +0 -1
- package/dist/utils/detectEnabledPlugins.js +0 -2
- package/dist/utils/firstUserAdmin.d.ts +0 -1
- package/dist/utils/firstUserAdmin.js +0 -2
- package/dist/utils/generateScopes.d.ts +0 -1
- package/dist/utils/generateScopes.js +0 -2
- package/dist/utils/session.d.ts +0 -1
- package/dist/utils/session.js +0 -2
- package/package.json +34 -91
- package/dist/adapter/collections.d.ts.map +0 -1
- package/dist/adapter/collections.js.map +0 -1
- package/dist/adapter/index.d.ts.map +0 -1
- package/dist/adapter/index.js.map +0 -1
- package/dist/components/BeforeLogin.d.ts.map +0 -1
- package/dist/components/BeforeLogin.js.map +0 -1
- package/dist/components/LoginView.d.ts.map +0 -1
- package/dist/components/LoginView.js.map +0 -1
- package/dist/components/LoginViewWrapper.d.ts.map +0 -1
- package/dist/components/LoginViewWrapper.js.map +0 -1
- package/dist/components/LogoutButton.d.ts.map +0 -1
- package/dist/components/LogoutButton.js.map +0 -1
- package/dist/components/PasskeyRegisterButton.d.ts.map +0 -1
- package/dist/components/PasskeyRegisterButton.js.map +0 -1
- package/dist/components/PasskeySignInButton.d.ts.map +0 -1
- package/dist/components/PasskeySignInButton.js.map +0 -1
- package/dist/components/auth/ForgotPasswordView.d.ts.map +0 -1
- package/dist/components/auth/ForgotPasswordView.js.map +0 -1
- package/dist/components/auth/ResetPasswordView.d.ts.map +0 -1
- package/dist/components/auth/ResetPasswordView.js.map +0 -1
- package/dist/components/auth/index.d.ts.map +0 -1
- package/dist/components/auth/index.js.map +0 -1
- package/dist/components/management/ApiKeysManagementClient.d.ts.map +0 -1
- package/dist/components/management/ApiKeysManagementClient.js.map +0 -1
- package/dist/components/management/PasskeysManagementClient.d.ts.map +0 -1
- package/dist/components/management/PasskeysManagementClient.js.map +0 -1
- package/dist/components/management/SecurityNavLinks.d.ts.map +0 -1
- package/dist/components/management/SecurityNavLinks.js.map +0 -1
- package/dist/components/management/TwoFactorManagementClient.d.ts.map +0 -1
- package/dist/components/management/TwoFactorManagementClient.js.map +0 -1
- package/dist/components/management/index.d.ts.map +0 -1
- package/dist/components/management/index.js.map +0 -1
- package/dist/components/management/views/ApiKeysView.d.ts.map +0 -1
- package/dist/components/management/views/ApiKeysView.js.map +0 -1
- package/dist/components/management/views/PasskeysView.d.ts.map +0 -1
- package/dist/components/management/views/PasskeysView.js.map +0 -1
- package/dist/components/management/views/TwoFactorView.d.ts.map +0 -1
- package/dist/components/management/views/TwoFactorView.js.map +0 -1
- package/dist/components/management/views/index.d.ts.map +0 -1
- package/dist/components/management/views/index.js.map +0 -1
- package/dist/components/twoFactor/TwoFactorSetupView.d.ts.map +0 -1
- package/dist/components/twoFactor/TwoFactorSetupView.js.map +0 -1
- package/dist/components/twoFactor/TwoFactorVerifyView.d.ts.map +0 -1
- package/dist/components/twoFactor/TwoFactorVerifyView.js.map +0 -1
- package/dist/components/twoFactor/index.d.ts.map +0 -1
- package/dist/components/twoFactor/index.js.map +0 -1
- package/dist/exports/client.d.ts.map +0 -1
- package/dist/exports/client.js.map +0 -1
- package/dist/exports/components.d.ts.map +0 -1
- package/dist/exports/components.js.map +0 -1
- package/dist/exports/management.d.ts.map +0 -1
- package/dist/exports/management.js.map +0 -1
- package/dist/exports/rsc.d.ts.map +0 -1
- package/dist/exports/rsc.js.map +0 -1
- package/dist/generated-types.d.ts.map +0 -1
- package/dist/generated-types.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/plugin/index.d.ts.map +0 -1
- package/dist/plugin/index.js.map +0 -1
- package/dist/scripts/generate-types.d.ts.map +0 -1
- package/dist/scripts/generate-types.js.map +0 -1
- package/dist/types/apiKey.d.ts.map +0 -1
- package/dist/types/apiKey.js.map +0 -1
- package/dist/types/betterAuth.d.ts.map +0 -1
- package/dist/types/betterAuth.js.map +0 -1
- package/dist/utils/access.d.ts.map +0 -1
- package/dist/utils/access.js.map +0 -1
- package/dist/utils/apiKeyAccess.d.ts.map +0 -1
- package/dist/utils/apiKeyAccess.js.map +0 -1
- package/dist/utils/betterAuthDefaults.d.ts.map +0 -1
- package/dist/utils/betterAuthDefaults.js.map +0 -1
- package/dist/utils/detectAuthConfig.d.ts.map +0 -1
- package/dist/utils/detectAuthConfig.js.map +0 -1
- package/dist/utils/detectEnabledPlugins.d.ts.map +0 -1
- package/dist/utils/detectEnabledPlugins.js.map +0 -1
- package/dist/utils/firstUserAdmin.d.ts.map +0 -1
- package/dist/utils/firstUserAdmin.js.map +0 -1
- package/dist/utils/generateScopes.d.ts.map +0 -1
- package/dist/utils/generateScopes.js.map +0 -1
- package/dist/utils/session.d.ts.map +0 -1
- package/dist/utils/session.js.map +0 -1
- package/src/adapter/collections.ts +0 -621
- package/src/adapter/index.ts +0 -712
- package/src/components/BeforeLogin.tsx +0 -39
- package/src/components/LoginView.tsx +0 -1516
- package/src/components/LoginViewWrapper.tsx +0 -35
- package/src/components/LogoutButton.tsx +0 -58
- package/src/components/PasskeyRegisterButton.tsx +0 -105
- package/src/components/PasskeySignInButton.tsx +0 -96
- package/src/components/auth/ForgotPasswordView.tsx +0 -274
- package/src/components/auth/ResetPasswordView.tsx +0 -331
- package/src/components/auth/index.ts +0 -8
- package/src/components/management/ApiKeysManagementClient.tsx +0 -988
- package/src/components/management/PasskeysManagementClient.tsx +0 -409
- package/src/components/management/SecurityNavLinks.tsx +0 -117
- package/src/components/management/TwoFactorManagementClient.tsx +0 -560
- package/src/components/management/index.ts +0 -20
- package/src/components/management/views/ApiKeysView.tsx +0 -57
- package/src/components/management/views/PasskeysView.tsx +0 -42
- package/src/components/management/views/TwoFactorView.tsx +0 -42
- package/src/components/management/views/index.ts +0 -10
- package/src/components/twoFactor/TwoFactorSetupView.tsx +0 -515
- package/src/components/twoFactor/TwoFactorVerifyView.tsx +0 -238
- package/src/components/twoFactor/index.ts +0 -8
- package/src/exports/client.ts +0 -77
- package/src/exports/components.ts +0 -30
- package/src/exports/management.ts +0 -25
- package/src/exports/rsc.ts +0 -11
- package/src/generated-types.ts +0 -269
- package/src/index.ts +0 -135
- package/src/plugin/index.ts +0 -834
- package/src/scripts/generate-types.ts +0 -269
- package/src/types/apiKey.ts +0 -63
- package/src/types/betterAuth.ts +0 -253
- package/src/utils/access.ts +0 -410
- package/src/utils/apiKeyAccess.ts +0 -443
- package/src/utils/betterAuthDefaults.ts +0 -102
- package/src/utils/detectAuthConfig.ts +0 -47
- package/src/utils/detectEnabledPlugins.ts +0 -69
- package/src/utils/firstUserAdmin.ts +0 -164
- package/src/utils/generateScopes.ts +0 -150
- package/src/utils/session.ts +0 -91
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import type { AdminViewProps } from 'payload'
|
|
2
|
-
import { LoginView, type LoginViewProps } from './LoginView.js'
|
|
3
|
-
|
|
4
|
-
type LoginConfig = Omit<LoginViewProps, 'authClient' | 'logo'>
|
|
5
|
-
|
|
6
|
-
type LoginViewWrapperProps = AdminViewProps
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Server component wrapper for LoginView.
|
|
10
|
-
* Reads login configuration from payload.config.custom.betterAuth.login
|
|
11
|
-
* and passes it as props to the client LoginView component.
|
|
12
|
-
*/
|
|
13
|
-
export async function LoginViewWrapper({ initPageResult }: LoginViewWrapperProps) {
|
|
14
|
-
const { req } = initPageResult
|
|
15
|
-
const { payload } = req
|
|
16
|
-
|
|
17
|
-
// Read login config from payload.config.custom.betterAuth.login
|
|
18
|
-
const loginConfig = (payload.config.custom?.betterAuth?.login ?? {}) as LoginConfig
|
|
19
|
-
|
|
20
|
-
return (
|
|
21
|
-
<LoginView
|
|
22
|
-
afterLoginPath={loginConfig.afterLoginPath}
|
|
23
|
-
requiredRole={loginConfig.requiredRole}
|
|
24
|
-
requireAllRoles={loginConfig.requireAllRoles}
|
|
25
|
-
enablePasskey={loginConfig.enablePasskey}
|
|
26
|
-
enableSignUp={loginConfig.enableSignUp}
|
|
27
|
-
defaultSignUpRole={loginConfig.defaultSignUpRole}
|
|
28
|
-
enableForgotPassword={loginConfig.enableForgotPassword}
|
|
29
|
-
resetPasswordUrl={loginConfig.resetPasswordUrl}
|
|
30
|
-
title={loginConfig.title}
|
|
31
|
-
/>
|
|
32
|
-
)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export default LoginViewWrapper
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useState } from 'react'
|
|
4
|
-
import { useRouter } from 'next/navigation.js'
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Logout button component styled to match Payload's admin nav.
|
|
8
|
-
* Uses Payload's CSS classes and variables for native theme integration.
|
|
9
|
-
*/
|
|
10
|
-
export function LogoutButton() {
|
|
11
|
-
const router = useRouter()
|
|
12
|
-
const [isLoading, setIsLoading] = useState(false)
|
|
13
|
-
|
|
14
|
-
async function handleLogout() {
|
|
15
|
-
if (isLoading) return
|
|
16
|
-
setIsLoading(true)
|
|
17
|
-
|
|
18
|
-
try {
|
|
19
|
-
await fetch('/api/auth/sign-out', {
|
|
20
|
-
method: 'POST',
|
|
21
|
-
credentials: 'include',
|
|
22
|
-
headers: {
|
|
23
|
-
'Content-Type': 'application/json',
|
|
24
|
-
},
|
|
25
|
-
body: JSON.stringify({}),
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
router.push('/admin/login')
|
|
29
|
-
} catch (error) {
|
|
30
|
-
console.error('[better-auth] Logout error:', error)
|
|
31
|
-
setIsLoading(false)
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return (
|
|
36
|
-
<button
|
|
37
|
-
onClick={handleLogout}
|
|
38
|
-
disabled={isLoading}
|
|
39
|
-
type="button"
|
|
40
|
-
className="nav__link"
|
|
41
|
-
style={{
|
|
42
|
-
background: 'none',
|
|
43
|
-
border: 'none',
|
|
44
|
-
cursor: isLoading ? 'not-allowed' : 'pointer',
|
|
45
|
-
opacity: isLoading ? 0.7 : 1,
|
|
46
|
-
width: '100%',
|
|
47
|
-
textAlign: 'left',
|
|
48
|
-
padding: 0,
|
|
49
|
-
}}
|
|
50
|
-
>
|
|
51
|
-
<span className="nav__link-label">
|
|
52
|
-
{isLoading ? 'Logging out...' : 'Log out'}
|
|
53
|
-
</span>
|
|
54
|
-
</button>
|
|
55
|
-
)
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export default LogoutButton
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useState, type ButtonHTMLAttributes } from 'react'
|
|
4
|
-
import {
|
|
5
|
-
createPayloadAuthClient,
|
|
6
|
-
type PayloadAuthClient,
|
|
7
|
-
} from '../exports/client.js'
|
|
8
|
-
|
|
9
|
-
export type PasskeyRegisterButtonProps = Omit<
|
|
10
|
-
ButtonHTMLAttributes<HTMLButtonElement>,
|
|
11
|
-
'onClick'
|
|
12
|
-
> & {
|
|
13
|
-
/** Optional pre-configured auth client */
|
|
14
|
-
authClient?: PayloadAuthClient
|
|
15
|
-
/** Optional name for the passkey */
|
|
16
|
-
passkeyName?: string
|
|
17
|
-
/** Callback when registration succeeds */
|
|
18
|
-
onSuccess?: (passkey: { id: string; name?: string }) => void
|
|
19
|
-
/** Callback when registration fails */
|
|
20
|
-
onError?: (error: string) => void
|
|
21
|
-
/** Button text when idle. Default: 'Add Passkey' */
|
|
22
|
-
label?: string
|
|
23
|
-
/** Button text when loading. Default: 'Registering...' */
|
|
24
|
-
loadingLabel?: string
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Standalone passkey registration button component.
|
|
29
|
-
* Handles the WebAuthn registration flow with Better Auth.
|
|
30
|
-
*
|
|
31
|
-
* @example
|
|
32
|
-
* ```tsx
|
|
33
|
-
* import { PasskeyRegisterButton } from '@delmaredigital/payload-better-auth/components'
|
|
34
|
-
*
|
|
35
|
-
* function SecuritySettings() {
|
|
36
|
-
* return (
|
|
37
|
-
* <PasskeyRegisterButton
|
|
38
|
-
* passkeyName="My MacBook"
|
|
39
|
-
* onSuccess={(passkey) => {
|
|
40
|
-
* console.log('Passkey registered:', passkey.id)
|
|
41
|
-
* refetchPasskeys()
|
|
42
|
-
* }}
|
|
43
|
-
* onError={(error) => {
|
|
44
|
-
* setError(error)
|
|
45
|
-
* }}
|
|
46
|
-
* />
|
|
47
|
-
* )
|
|
48
|
-
* }
|
|
49
|
-
* ```
|
|
50
|
-
*/
|
|
51
|
-
export function PasskeyRegisterButton({
|
|
52
|
-
authClient: providedClient,
|
|
53
|
-
passkeyName,
|
|
54
|
-
onSuccess,
|
|
55
|
-
onError,
|
|
56
|
-
label = 'Add Passkey',
|
|
57
|
-
loadingLabel = 'Registering...',
|
|
58
|
-
disabled,
|
|
59
|
-
children,
|
|
60
|
-
...buttonProps
|
|
61
|
-
}: PasskeyRegisterButtonProps) {
|
|
62
|
-
const [loading, setLoading] = useState(false)
|
|
63
|
-
|
|
64
|
-
async function handleClick() {
|
|
65
|
-
setLoading(true)
|
|
66
|
-
|
|
67
|
-
try {
|
|
68
|
-
const client = providedClient ?? createPayloadAuthClient()
|
|
69
|
-
const result = await client.passkey.addPasskey({
|
|
70
|
-
name: passkeyName,
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
if (result.error) {
|
|
74
|
-
onError?.(result.error.message ?? 'Passkey registration failed')
|
|
75
|
-
} else if (result.data) {
|
|
76
|
-
onSuccess?.({ id: result.data.id, name: passkeyName })
|
|
77
|
-
}
|
|
78
|
-
} catch (err) {
|
|
79
|
-
if (err instanceof Error && err.name === 'NotAllowedError') {
|
|
80
|
-
onError?.('Passkey registration was cancelled or not allowed')
|
|
81
|
-
} else if (err instanceof Error && err.name === 'InvalidStateError') {
|
|
82
|
-
onError?.('This passkey is already registered')
|
|
83
|
-
} else {
|
|
84
|
-
onError?.(
|
|
85
|
-
err instanceof Error ? err.message : 'Passkey registration failed'
|
|
86
|
-
)
|
|
87
|
-
}
|
|
88
|
-
} finally {
|
|
89
|
-
setLoading(false)
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return (
|
|
94
|
-
<button
|
|
95
|
-
type="button"
|
|
96
|
-
onClick={handleClick}
|
|
97
|
-
disabled={disabled || loading}
|
|
98
|
-
{...buttonProps}
|
|
99
|
-
>
|
|
100
|
-
{children ?? (loading ? loadingLabel : label)}
|
|
101
|
-
</button>
|
|
102
|
-
)
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
export default PasskeyRegisterButton
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useState, type ButtonHTMLAttributes } from 'react'
|
|
4
|
-
import {
|
|
5
|
-
createPayloadAuthClient,
|
|
6
|
-
type PayloadAuthClient,
|
|
7
|
-
} from '../exports/client.js'
|
|
8
|
-
|
|
9
|
-
export type PasskeySignInButtonProps = Omit<
|
|
10
|
-
ButtonHTMLAttributes<HTMLButtonElement>,
|
|
11
|
-
'onClick'
|
|
12
|
-
> & {
|
|
13
|
-
/** Optional pre-configured auth client */
|
|
14
|
-
authClient?: PayloadAuthClient
|
|
15
|
-
/** Callback when sign-in succeeds */
|
|
16
|
-
onSuccess?: (user: { id: string; email: string; role?: string }) => void
|
|
17
|
-
/** Callback when sign-in fails */
|
|
18
|
-
onError?: (error: string) => void
|
|
19
|
-
/** Button text when idle. Default: 'Sign in with Passkey' */
|
|
20
|
-
label?: string
|
|
21
|
-
/** Button text when loading. Default: 'Authenticating...' */
|
|
22
|
-
loadingLabel?: string
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Standalone passkey sign-in button component.
|
|
27
|
-
* Handles the WebAuthn authentication flow with Better Auth.
|
|
28
|
-
*
|
|
29
|
-
* @example
|
|
30
|
-
* ```tsx
|
|
31
|
-
* import { PasskeySignInButton } from '@delmaredigital/payload-better-auth/components'
|
|
32
|
-
*
|
|
33
|
-
* function LoginForm() {
|
|
34
|
-
* return (
|
|
35
|
-
* <PasskeySignInButton
|
|
36
|
-
* onSuccess={(user) => {
|
|
37
|
-
* router.push('/dashboard')
|
|
38
|
-
* }}
|
|
39
|
-
* onError={(error) => {
|
|
40
|
-
* setError(error)
|
|
41
|
-
* }}
|
|
42
|
-
* />
|
|
43
|
-
* )
|
|
44
|
-
* }
|
|
45
|
-
* ```
|
|
46
|
-
*/
|
|
47
|
-
export function PasskeySignInButton({
|
|
48
|
-
authClient: providedClient,
|
|
49
|
-
onSuccess,
|
|
50
|
-
onError,
|
|
51
|
-
label = 'Sign in with Passkey',
|
|
52
|
-
loadingLabel = 'Authenticating...',
|
|
53
|
-
disabled,
|
|
54
|
-
children,
|
|
55
|
-
...buttonProps
|
|
56
|
-
}: PasskeySignInButtonProps) {
|
|
57
|
-
const [loading, setLoading] = useState(false)
|
|
58
|
-
|
|
59
|
-
async function handleClick() {
|
|
60
|
-
setLoading(true)
|
|
61
|
-
|
|
62
|
-
try {
|
|
63
|
-
const client = providedClient ?? createPayloadAuthClient()
|
|
64
|
-
const result = await client.signIn.passkey()
|
|
65
|
-
|
|
66
|
-
if (result.error) {
|
|
67
|
-
onError?.(result.error.message ?? 'Passkey authentication failed')
|
|
68
|
-
} else if (result.data?.user) {
|
|
69
|
-
onSuccess?.(result.data.user as { id: string; email: string; role?: string })
|
|
70
|
-
}
|
|
71
|
-
} catch (err) {
|
|
72
|
-
if (err instanceof Error && err.name === 'NotAllowedError') {
|
|
73
|
-
onError?.('Passkey authentication was cancelled or not allowed')
|
|
74
|
-
} else {
|
|
75
|
-
onError?.(
|
|
76
|
-
err instanceof Error ? err.message : 'Passkey authentication failed'
|
|
77
|
-
)
|
|
78
|
-
}
|
|
79
|
-
} finally {
|
|
80
|
-
setLoading(false)
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
return (
|
|
85
|
-
<button
|
|
86
|
-
type="button"
|
|
87
|
-
onClick={handleClick}
|
|
88
|
-
disabled={disabled || loading}
|
|
89
|
-
{...buttonProps}
|
|
90
|
-
>
|
|
91
|
-
{children ?? (loading ? loadingLabel : label)}
|
|
92
|
-
</button>
|
|
93
|
-
)
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export default PasskeySignInButton
|
|
@@ -1,274 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useState, type FormEvent } from 'react'
|
|
4
|
-
|
|
5
|
-
export type ForgotPasswordViewProps = {
|
|
6
|
-
/** Custom logo element */
|
|
7
|
-
logo?: React.ReactNode
|
|
8
|
-
/** Page title. Default: 'Forgot Password' */
|
|
9
|
-
title?: string
|
|
10
|
-
/** Path to login page. Default: '/admin/login' */
|
|
11
|
-
loginPath?: string
|
|
12
|
-
/** Success message to show after email is sent */
|
|
13
|
-
successMessage?: string
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Forgot password page component for requesting a password reset email.
|
|
18
|
-
* Uses Better Auth's forgetPassword endpoint.
|
|
19
|
-
*/
|
|
20
|
-
export function ForgotPasswordView({
|
|
21
|
-
logo,
|
|
22
|
-
title = 'Forgot Password',
|
|
23
|
-
loginPath = '/admin/login',
|
|
24
|
-
successMessage = 'If an account exists with this email, you will receive a password reset link.',
|
|
25
|
-
}: ForgotPasswordViewProps) {
|
|
26
|
-
const [email, setEmail] = useState('')
|
|
27
|
-
const [error, setError] = useState<string | null>(null)
|
|
28
|
-
const [success, setSuccess] = useState(false)
|
|
29
|
-
const [loading, setLoading] = useState(false)
|
|
30
|
-
|
|
31
|
-
async function handleSubmit(e: FormEvent) {
|
|
32
|
-
e.preventDefault()
|
|
33
|
-
setLoading(true)
|
|
34
|
-
setError(null)
|
|
35
|
-
|
|
36
|
-
try {
|
|
37
|
-
const response = await fetch('/api/auth/forget-password', {
|
|
38
|
-
method: 'POST',
|
|
39
|
-
headers: { 'Content-Type': 'application/json' },
|
|
40
|
-
credentials: 'include',
|
|
41
|
-
body: JSON.stringify({
|
|
42
|
-
email,
|
|
43
|
-
redirectTo: `${window.location.origin}/admin/reset-password`,
|
|
44
|
-
}),
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
if (response.ok) {
|
|
48
|
-
setSuccess(true)
|
|
49
|
-
} else {
|
|
50
|
-
// Always show success message to prevent email enumeration
|
|
51
|
-
setSuccess(true)
|
|
52
|
-
}
|
|
53
|
-
} catch {
|
|
54
|
-
setError('An error occurred. Please try again.')
|
|
55
|
-
} finally {
|
|
56
|
-
setLoading(false)
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (success) {
|
|
61
|
-
return (
|
|
62
|
-
<div
|
|
63
|
-
style={{
|
|
64
|
-
minHeight: '100vh',
|
|
65
|
-
display: 'flex',
|
|
66
|
-
alignItems: 'center',
|
|
67
|
-
justifyContent: 'center',
|
|
68
|
-
background: 'var(--theme-bg)',
|
|
69
|
-
padding: 'var(--base)',
|
|
70
|
-
}}
|
|
71
|
-
>
|
|
72
|
-
<div
|
|
73
|
-
style={{
|
|
74
|
-
background: 'var(--theme-elevation-50)',
|
|
75
|
-
padding: 'calc(var(--base) * 2)',
|
|
76
|
-
borderRadius: 'var(--style-radius-m)',
|
|
77
|
-
boxShadow: '0 2px 20px rgba(0, 0, 0, 0.1)',
|
|
78
|
-
width: '100%',
|
|
79
|
-
maxWidth: '400px',
|
|
80
|
-
textAlign: 'center',
|
|
81
|
-
}}
|
|
82
|
-
>
|
|
83
|
-
{logo && (
|
|
84
|
-
<div style={{ marginBottom: 'calc(var(--base) * 1.5)' }}>
|
|
85
|
-
{logo}
|
|
86
|
-
</div>
|
|
87
|
-
)}
|
|
88
|
-
|
|
89
|
-
<h1
|
|
90
|
-
style={{
|
|
91
|
-
color: 'var(--theme-text)',
|
|
92
|
-
fontSize: 'var(--font-size-h3)',
|
|
93
|
-
fontWeight: 600,
|
|
94
|
-
margin: '0 0 var(--base) 0',
|
|
95
|
-
}}
|
|
96
|
-
>
|
|
97
|
-
Check Your Email
|
|
98
|
-
</h1>
|
|
99
|
-
|
|
100
|
-
<p
|
|
101
|
-
style={{
|
|
102
|
-
color: 'var(--theme-text)',
|
|
103
|
-
opacity: 0.8,
|
|
104
|
-
marginBottom: 'calc(var(--base) * 1.5)',
|
|
105
|
-
fontSize: 'var(--font-size-small)',
|
|
106
|
-
}}
|
|
107
|
-
>
|
|
108
|
-
{successMessage}
|
|
109
|
-
</p>
|
|
110
|
-
|
|
111
|
-
<a
|
|
112
|
-
href={loginPath}
|
|
113
|
-
style={{
|
|
114
|
-
color: 'var(--theme-elevation-800)',
|
|
115
|
-
fontSize: 'var(--font-size-small)',
|
|
116
|
-
textDecoration: 'underline',
|
|
117
|
-
}}
|
|
118
|
-
>
|
|
119
|
-
Back to login
|
|
120
|
-
</a>
|
|
121
|
-
</div>
|
|
122
|
-
</div>
|
|
123
|
-
)
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return (
|
|
127
|
-
<div
|
|
128
|
-
style={{
|
|
129
|
-
minHeight: '100vh',
|
|
130
|
-
display: 'flex',
|
|
131
|
-
alignItems: 'center',
|
|
132
|
-
justifyContent: 'center',
|
|
133
|
-
background: 'var(--theme-bg)',
|
|
134
|
-
padding: 'var(--base)',
|
|
135
|
-
}}
|
|
136
|
-
>
|
|
137
|
-
<div
|
|
138
|
-
style={{
|
|
139
|
-
background: 'var(--theme-elevation-50)',
|
|
140
|
-
padding: 'calc(var(--base) * 2)',
|
|
141
|
-
borderRadius: 'var(--style-radius-m)',
|
|
142
|
-
boxShadow: '0 2px 20px rgba(0, 0, 0, 0.1)',
|
|
143
|
-
width: '100%',
|
|
144
|
-
maxWidth: '400px',
|
|
145
|
-
}}
|
|
146
|
-
>
|
|
147
|
-
{logo && (
|
|
148
|
-
<div
|
|
149
|
-
style={{
|
|
150
|
-
textAlign: 'center',
|
|
151
|
-
marginBottom: 'calc(var(--base) * 1.5)',
|
|
152
|
-
}}
|
|
153
|
-
>
|
|
154
|
-
{logo}
|
|
155
|
-
</div>
|
|
156
|
-
)}
|
|
157
|
-
|
|
158
|
-
<h1
|
|
159
|
-
style={{
|
|
160
|
-
color: 'var(--theme-text)',
|
|
161
|
-
fontSize: 'var(--font-size-h3)',
|
|
162
|
-
fontWeight: 600,
|
|
163
|
-
marginBottom: 'calc(var(--base) * 0.5)',
|
|
164
|
-
textAlign: 'center',
|
|
165
|
-
margin: '0 0 calc(var(--base) * 0.5) 0',
|
|
166
|
-
}}
|
|
167
|
-
>
|
|
168
|
-
{title}
|
|
169
|
-
</h1>
|
|
170
|
-
|
|
171
|
-
<p
|
|
172
|
-
style={{
|
|
173
|
-
color: 'var(--theme-text)',
|
|
174
|
-
opacity: 0.7,
|
|
175
|
-
fontSize: 'var(--font-size-small)',
|
|
176
|
-
textAlign: 'center',
|
|
177
|
-
marginBottom: 'calc(var(--base) * 1.5)',
|
|
178
|
-
}}
|
|
179
|
-
>
|
|
180
|
-
Enter your email and we'll send you a reset link.
|
|
181
|
-
</p>
|
|
182
|
-
|
|
183
|
-
<form onSubmit={handleSubmit}>
|
|
184
|
-
<div style={{ marginBottom: 'calc(var(--base) * 1.5)' }}>
|
|
185
|
-
<label
|
|
186
|
-
htmlFor="email"
|
|
187
|
-
style={{
|
|
188
|
-
display: 'block',
|
|
189
|
-
color: 'var(--theme-text)',
|
|
190
|
-
marginBottom: 'calc(var(--base) * 0.5)',
|
|
191
|
-
fontSize: 'var(--font-size-small)',
|
|
192
|
-
fontWeight: 500,
|
|
193
|
-
}}
|
|
194
|
-
>
|
|
195
|
-
Email
|
|
196
|
-
</label>
|
|
197
|
-
<input
|
|
198
|
-
id="email"
|
|
199
|
-
type="email"
|
|
200
|
-
value={email}
|
|
201
|
-
onChange={(e) => setEmail(e.target.value)}
|
|
202
|
-
required
|
|
203
|
-
autoComplete="email"
|
|
204
|
-
style={{
|
|
205
|
-
width: '100%',
|
|
206
|
-
padding: 'calc(var(--base) * 0.75)',
|
|
207
|
-
background: 'var(--theme-input-bg)',
|
|
208
|
-
border: '1px solid var(--theme-elevation-150)',
|
|
209
|
-
borderRadius: 'var(--style-radius-s)',
|
|
210
|
-
color: 'var(--theme-text)',
|
|
211
|
-
fontSize: 'var(--font-size-base)',
|
|
212
|
-
outline: 'none',
|
|
213
|
-
boxSizing: 'border-box',
|
|
214
|
-
}}
|
|
215
|
-
/>
|
|
216
|
-
</div>
|
|
217
|
-
|
|
218
|
-
{error && (
|
|
219
|
-
<div
|
|
220
|
-
style={{
|
|
221
|
-
color: 'var(--theme-error-500)',
|
|
222
|
-
marginBottom: 'var(--base)',
|
|
223
|
-
fontSize: 'var(--font-size-small)',
|
|
224
|
-
padding: 'calc(var(--base) * 0.5)',
|
|
225
|
-
background: 'var(--theme-error-50)',
|
|
226
|
-
borderRadius: 'var(--style-radius-s)',
|
|
227
|
-
border: '1px solid var(--theme-error-200)',
|
|
228
|
-
}}
|
|
229
|
-
>
|
|
230
|
-
{error}
|
|
231
|
-
</div>
|
|
232
|
-
)}
|
|
233
|
-
|
|
234
|
-
<button
|
|
235
|
-
type="submit"
|
|
236
|
-
disabled={loading}
|
|
237
|
-
style={{
|
|
238
|
-
width: '100%',
|
|
239
|
-
padding: 'calc(var(--base) * 0.75)',
|
|
240
|
-
background: 'var(--theme-elevation-800)',
|
|
241
|
-
border: 'none',
|
|
242
|
-
borderRadius: 'var(--style-radius-s)',
|
|
243
|
-
color: 'var(--theme-elevation-50)',
|
|
244
|
-
fontSize: 'var(--font-size-base)',
|
|
245
|
-
fontWeight: 500,
|
|
246
|
-
cursor: loading ? 'not-allowed' : 'pointer',
|
|
247
|
-
opacity: loading ? 0.7 : 1,
|
|
248
|
-
transition: 'opacity 150ms ease',
|
|
249
|
-
marginBottom: 'var(--base)',
|
|
250
|
-
}}
|
|
251
|
-
>
|
|
252
|
-
{loading ? 'Sending...' : 'Send Reset Link'}
|
|
253
|
-
</button>
|
|
254
|
-
|
|
255
|
-
<div style={{ textAlign: 'center' }}>
|
|
256
|
-
<a
|
|
257
|
-
href={loginPath}
|
|
258
|
-
style={{
|
|
259
|
-
color: 'var(--theme-text)',
|
|
260
|
-
opacity: 0.7,
|
|
261
|
-
fontSize: 'var(--font-size-small)',
|
|
262
|
-
textDecoration: 'underline',
|
|
263
|
-
}}
|
|
264
|
-
>
|
|
265
|
-
Back to login
|
|
266
|
-
</a>
|
|
267
|
-
</div>
|
|
268
|
-
</form>
|
|
269
|
-
</div>
|
|
270
|
-
</div>
|
|
271
|
-
)
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
export default ForgotPasswordView
|