Custom UI for Authentication

While Account Kit provides pre-built UI components for authentication, you may want to create your own custom UI to match your application’s design system. This section covers how to implement custom authentication flows using Account Kit hooks.

Tailwind CSS is a required dependency for using Alchemy Account Kit UI components. However, Alchemy Account Kit hooks function independently and do not require Tailwind.

Available Authentication Methods

Account Kit supports several authentication methods that you can implement with custom UI. Each method has its own dedicated page with detailed implementation instructions, code examples, and specific parameters for the authentication hooks:

Visit each method’s dedicated page for specific implementation details, including the exact parameters to use with the useAuthenticate hook for that authentication method.

Core Hooks for Custom UI

The following section provides an overview of the main hooks you’ll use when implementing custom authentication UI. These hooks are the foundation for all authentication methods, but their specific usage and parameters vary depending on the authentication method you choose.

useAuthenticate

The useAuthenticate hook is the foundation for all authentication methods. It provides the authenticate function that handles the authentication process.

If MFA is required (e.g., the user has added an authenticator app), the authenticate function will throw an MfaRequiredError or request a multiFactorCode. See the MFA docs for a detailed example of handling TOTP codes.

import React from "react";
import { 
function useAuthenticate(mutationArgs?: UseAuthenticateMutationArgs): UseAuthenticateResult

Hook that provides functions and state for authenticating a user using a signer. It includes methods for both synchronous and asynchronous mutations. Useful if building your own UI components and want to control the authentication flow. For authenticate vs authenticateAsync, use authenticate when you want the hook the handle state changes for you, authenticateAsync when you need to wait for the result to finish processing.

This can be complex for magic link or OTP flows: OPT calls authenticate twice, but this should be handled by the signer.

useAuthenticate
} from "@account-kit/react";
function
function MyAuthComponent(): void
MyAuthComponent
() {
const {
const authenticate: UseMutateFunction<User, Error, AuthParams, unknown>
authenticate
,
const authenticateAsync: UseMutateAsyncFunction<User, Error, AuthParams, unknown>
authenticateAsync
,
const isPending: boolean
isPending
} =
function useAuthenticate(mutationArgs?: UseAuthenticateMutationArgs): UseAuthenticateResult

Hook that provides functions and state for authenticating a user using a signer. It includes methods for both synchronous and asynchronous mutations. Useful if building your own UI components and want to control the authentication flow. For authenticate vs authenticateAsync, use authenticate when you want the hook the handle state changes for you, authenticateAsync when you need to wait for the result to finish processing.

This can be complex for magic link or OTP flows: OPT calls authenticate twice, but this should be handled by the signer.

useAuthenticate
();
// Use authenticate with different parameters based on auth method // The specific parameters depend on the authentication method // See the individual authentication method pages for details }

useUser

The useUser hook returns the current user information from either an External Owned Account (EOA) or from a Smart Contract Account (SCA). This is the best way to check if a user is logged in regardless of account type.

import React from "react";
import { 
const useUser: () => UseUserResult

A React hook that returns the current user information, either from an External Owned Account (EOA) or from the client store. It uses the Alchemy account context and synchronizes with external store updates. The best way to check if user is logged in for both smart account contract users and EOA.

If using smart contract account, returns address of the signer. If only using smart account contracts then you can use useSignerStatus or useAccount to see if the account is defined.

useUser
} from "@account-kit/react";
function
function MyComponent(): JSX.Element
MyComponent
() {
const
const user: UseUserResult
user
=
function useUser(): UseUserResult

A React hook that returns the current user information, either from an External Owned Account (EOA) or from the client store. It uses the Alchemy account context and synchronizes with external store updates. The best way to check if user is logged in for both smart account contract users and EOA.

If using smart contract account, returns address of the signer. If only using smart account contracts then you can use useSignerStatus or useAccount to see if the account is defined.

useUser
();
if (!
const user: UseUserResult
user
) {
return <
React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>Please log in</
React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>;
} return ( <
React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>
<
React.JSX.IntrinsicElements.p: React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p
>User address: {
const user: User & { type: "eoa" | "sca"; }
user
.
address: `0x${string}`
address
}</
React.JSX.IntrinsicElements.p: React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p
>
<
React.JSX.IntrinsicElements.p: React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p
>Account type: {
const user: User & { type: "eoa" | "sca"; }
user
.
type: "eoa" | "sca"
type
}</
React.JSX.IntrinsicElements.p: React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p
> {/* "eoa" or "sca" */}
</
React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>
); }

useAccount

The useAccount hook retrieves the smart contract account instance for the authenticated user. It’s primarily used to get the smart contract account address and interact with the account.

import React from "react";
import { 
function useAccount<TAccount extends SupportedAccountTypes>(params: UseAccountProps<TAccount>): UseAccountResult<TAccount>

Hook to subscribe to account state and interactions, including creation, connection, and status monitoring. It synchronizes with external store updates and provides status-dependent results. The supported account types are: LightAccount, MultiOwnerLightAccount, MultiOwnerModularAccount, and ModularAccountV2. Primarily used to get the smart account address before deployment. Dependent on the signer: if the signer has not been initialized and authenticated, address and isLoadingAccount return null.

If using a smart contract account, returns instance of a smart contract account that the user is connected to. Returns address of smart contract account, not address of the signer.

If using an EOA, returns address of signer

useAccount
} from "@account-kit/react";
function
function MyComponent(): JSX.Element
MyComponent
() {
const {
const account: ModularAccountV2<AlchemySigner> | undefined
account
,
const address: `0x${string}` | undefined
address
,
const isLoadingAccount: boolean
isLoadingAccount
} =
useAccount<"ModularAccountV2">(params: UseAccountProps<"ModularAccountV2">): UseAccountResult<"ModularAccountV2">

Hook to subscribe to account state and interactions, including creation, connection, and status monitoring. It synchronizes with external store updates and provides status-dependent results. The supported account types are: LightAccount, MultiOwnerLightAccount, MultiOwnerModularAccount, and ModularAccountV2. Primarily used to get the smart account address before deployment. Dependent on the signer: if the signer has not been initialized and authenticated, address and isLoadingAccount return null.

If using a smart contract account, returns instance of a smart contract account that the user is connected to. Returns address of smart contract account, not address of the signer.

If using an EOA, returns address of signer

useAccount
({
type: "ModularAccountV2"
type
: "ModularAccountV2", // Specify the account type you're using
}); if (
const isLoadingAccount: boolean
isLoadingAccount
) {
return <
React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>Loading account...</
React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>;
} if (!
const account: ModularAccountV2<AlchemySigner> | undefined
account
) {
return <
React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>Please log in to access your account</
React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>;
} return ( <
React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>
<
React.JSX.IntrinsicElements.p: React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p
>Smart contract account address: {
const address: `0x${string}` | undefined
address
}</
React.JSX.IntrinsicElements.p: React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p
>
{/* Now you can use the account instance for transactions */} </
React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>
); }

This hook:

  • Returns a smart contract account instance (account) when the user is logged in
  • Provides the smart contract account address, not the signer address
  • Returns undefined for both account and address when the user is not logged in
  • Includes an isLoadingAccount flag to handle loading states

Note: If you just need to check if a user is logged in (regardless of account type), consider using useUser instead.

Getting Started

To implement custom authentication UI:

  1. Choose an authentication method from the list above and visit its dedicated page
  2. Follow the method-specific implementation guidelines on that page
  3. Use the core hooks described above following the method-specific parameters
  4. Implement the UI components for your chosen authentication flow
  5. Handle success and error states appropriately

Each authentication method page provides detailed code examples tailored to that specific method, showing exactly how to configure the hooks and implement the entire authentication flow.