šŸ“ Sign Up | šŸ” Log In

← Root | ↑ Up

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā” │ šŸ“„ shadcn/directory/clerk/clerk-docs/_partials/custom-flows/email-link-verification │ ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

╔══════════════════════════════════════════════════════════════════════════════════════════════╗
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘

{/* Adds an email address to a user's account, and verifies it using an email link. */}

  1. Every user has a User object that represents their account. The User object has a emailAddresses property that contains all the email addresses associated with the user. The useUser() hook is used to get the User object.
  2. The User.createEmailAddress() method is passed to the useReverification() hook to require the user to reverify their credentials before being able to add an email address to their account.
  3. If the createEmailAddress() function is successful, a new EmailAddress object is created and stored in User.emailAddresses.
  4. The newly created EmailAddress object is used to access the createEmailLinkFlow() method.
  5. The createEmailLinkFlow() method is used to access the startEmailLinkFlow() method.
  6. The startEmailLinkFlow() method is called with the redirectUrl parameter set to /account/add-email/verify. It sends an email with a verification link to the user. When the user visits the link, they are redirected to the URL that was provided.
  7. On the /account/add-email/verify page, the useClerk() hook is used to get the handleEmailLinkVerification() method.
  8. The handleEmailLinkVerification() method is called to verify the email address. Error handling is included to handle any errors that occur during the verification process.

<Tabs items={["Next.js"]}> <Tab> <CodeBlockTabs options={["Add email page", "Verify page"]}> ```tsx {{ filename: 'app/account/add-email/page.tsx', collapsible: true }} 'use client'

  import * as React from 'react'
  import { useUser, useReverification } from '@clerk/nextjs'

  export default function Page() {
    const { isLoaded, isSignedIn, user } = useUser()
    const [email, setEmail] = React.useState('')
    const [verifying, setVerifying] = React.useState(false)
    const [error, setError] = React.useState('')
    const createEmailAddress = useReverification((email: string) =>
      user?.createEmailAddress({ email }),
    )

    if (!isLoaded) {
      // Handle loading state
      return null
    }

    if (!isSignedIn) {
      // Handle signed out state
      return <p>You must be signed in to access this page</p>
    }

    // Handle addition of the email address
    const handleSubmit = async (e: React.FormEvent) => {
      e.preventDefault()

      try {
        setVerifying(true)

        // Add an unverified email address to user
        const res = await createEmailAddress(email)
        // Reload user to get updated User object
        await user.reload()

        // Find the email address that was just added
        const emailAddress = user.emailAddresses.find((a) => a.id === res.id)

        if (!emailAddress) {
          setError('Email address not found')
          return
        }

        const { startEmailLinkFlow } = emailAddress.createEmailLinkFlow()

        // Dynamically set the host domain for dev and prod
        // You could instead use an environment variable or other source for the host domain
        const protocol = window.location.protocol
        const host = window.location.host

        // Send the user an email with the verification link
        startEmailLinkFlow({ redirectUrl: `${protocol}//${host}/account/add-email/verify` })
      } catch (err) {
        // See https://clerk.com/docs/guides/development/custom-flows/error-handling
        // for more info on error handling
        console.error(JSON.stringify(err, null, 2))
        setError('An error occurred.')
      }
    }

    async function reset(e: React.FormEvent) {
      e.preventDefault()
      setVerifying(false)
    }

    if (error) {
      return (
        <div>
          <p>Error: {error}</p>
          <button onClick={() => setError('')}>Try again</button>
        </div>
      )
    }

    if (verifying) {
      return (
        <div>
          <p>Check your email and visit the link that was sent to you.</p>
          <form onSubmit={reset}>
            <button type="submit">Restart</button>
          </form>
        </div>
      )
    }

    // Display the initial form to capture the email address
    return (
      <>
        <h1>Add email</h1>
        <div>
          <form onSubmit={(e) => handleSubmit(e)}>
            <input
              placeholder="Enter email address"
              type="email"
              value={email}
              onChange={(e) => setEmail(e.target.value)}
            />
            <button type="submit">Continue</button>
          </form>
        </div>
      </>
    )
  }
  ```

  ```tsx {{ filename: 'app/account/add-email/verify/page.tsx', collapsible: true }}
  'use client'

  import * as React from 'react'
  import { useClerk } from '@clerk/nextjs'
  import { EmailLinkErrorCodeStatus, isEmailLinkError } from '@clerk/nextjs/errors'
  import Link from 'next/link'

  export type VerificationStatus =
    | 'expired'
    | 'failed'
    | 'loading'
    | 'verified'
    | 'verified_switch_tab'
    | 'client_mismatch'

  export default function VerifyEmailLink() {
    const [verificationStatus, setVerificationStatus] = React.useState('loading')

    const { handleEmailLinkVerification, loaded } = useClerk()

    async function verify() {
      try {
        await handleEmailLinkVerification({})
        setVerificationStatus('verified')
      } catch (err: any) {
        let status: VerificationStatus = 'failed'

        if (isEmailLinkError(err)) {
          // If link expired, set status to expired
          if (err.code === EmailLinkErrorCodeStatus.Expired) {
            status = 'expired'
          } else if (err.code === EmailLinkErrorCodeStatus.ClientMismatch) {
            // OPTIONAL: This check is only required if you have
            // the 'Require the same device and browser' setting
            // enabled in the Clerk Dashboard
            status = 'client_mismatch'
          }
        }

        setVerificationStatus(status)
        return
      }
    }

    React.useEffect(() => {
      if (!loaded) return

      verify()
    }, [handleEmailLinkVerification, loaded])

    if (verificationStatus === 'loading') {
      return <div>Loading...</div>
    }

    if (verificationStatus === 'failed') {
      return (
        <div>
          <h1>Verify your email</h1>
          <p>The email link verification failed.</p>
          <Link href="/account/add-email">Return to add email</Link>
        </div>
      )
    }

    if (verificationStatus === 'expired') {
      return (
        <div>
          <h1>Verify your email</h1>
          <p>The email link has expired.</p>
          <Link href="/account/add-email">Return to add email</Link>
        </div>
      )
    }

    // OPTIONAL: This check is only required if you have
    // the 'Require the same device and browser' setting
    // enabled in the Clerk Dashboard
    if (verificationStatus === 'client_mismatch') {
      return (
        <div>
          <h1>Verify your email</h1>
          <p>
            You must complete the email link verification on the same device and browser as you
            started it on.
          </p>
          <Link href="/account/add-email">Return to add email</Link>
        </div>
      )
    }

    return (
      <div>
        <h1>Verify your email</h1>
        <p>Successfully added email!</p>
      </div>
    )
  }
  ```
</CodeBlockTabs>
</Tab> </Tabs>
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•

← Root | ↑ Up