Authentication with UI components
Account Kit allows you to use pre-built, highly customizable UI components to handle authenticating your users. These components provide flexibility to:
- Use the pre-built modal or embed the auth card directly in your app
- Choose from multiple authentication methods
- Customize authentication method UI
- Customize theme
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 pre-built UI components:
- Email OTP - One-time password sent via email
- Email Magic Link - Authentication links sent via email
- Social Login - Authentication with providers like Google and Facebook
- Custom Social Providers - Add custom OAuth providers via Auth0
- Passkey Signup - Create accounts with passkeys
- Passkey Login - Authenticate with existing passkeys
- Multi-Factor Authentication - Add an additional verification layer after initial login using an authenticator app
- EOA Login - Bring in your own EOAs
Each authentication method page includes specific configuration options and examples for both pre-built UI components and custom UI implementations.
Multi-Factor Authentication (MFA)
If your users have an authenticator app (TOTP) set up, the UI components will automatically prompt them for their 6-digit code after they complete any primary login method (e.g., Email OTP, Email Magic Link, or Social Login). No extra configuration is required in the UI component – just enable MFA for your users.
Modal auth
Assuming your application has been set up, using UI components is the easiest way to authenticate users. All you have to do is leverage the useAuthModal
hook and provide users a CTA to open the modal.
import React from "react";
import { const useAuthModal: () => {
isOpen: boolean;
openAuthModal: () => void;
closeAuthModal: () => void;
}A hook that returns the open and close functions for the Auth Modal if uiConfig is enabled on the Account Provider
useAuthModal } from "@account-kit/react";
export default function function MyPage(): JSX.ElementMyPage() {
const { const openAuthModal: () => voidopenAuthModal } = function useAuthModal(): {
isOpen: boolean;
openAuthModal: () => void;
closeAuthModal: () => void;
}A hook that returns the open and close functions for the Auth Modal if uiConfig is enabled on the Account Provider
useAuthModal();
return <React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>button React.DOMAttributes<HTMLButtonElement>.onClick?: React.MouseEventHandler<HTMLButtonElement> | undefinedonClick={const openAuthModal: () => voidopenAuthModal}>Authenticate</React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>button>;
}
That’s it! When the user clicks that button, the modal will open and they can complete authentication. Once they are authenticated, you can use the useAccount
hook to get the logged in user’s SCA address.
Want to display a loading state during authentication?
For authentication with redirects in a modal, you may want to add a loading state when users are waiting for authentication to complete.
To do this, manage the loading state directly using our hooks, as shown below. In embedded authentication and non-redirect flows, such as passkey authentication, we handle the loading state for you.
import { const useAuthModal: () => {
isOpen: boolean;
openAuthModal: () => void;
closeAuthModal: () => void;
}A hook that returns the open and close functions for the Auth Modal if uiConfig is enabled on the Account Provider
useAuthModal, const useSignerStatus: (override?: AlchemyAccountContextProps) => UseSignerStatusResultHook to get the signer status, optionally using an override configuration, useful if you’re building your own login.
useSignerStatus } from "@account-kit/react";
import { function useEffect(effect: React.EffectCallback, deps?: React.DependencyList): voidAccepts a function that contains imperative, possibly effectful code.
useEffect } from "react";
const { const openAuthModal: () => voidopenAuthModal } = function useAuthModal(): {
isOpen: boolean;
openAuthModal: () => void;
closeAuthModal: () => void;
}A hook that returns the open and close functions for the Auth Modal if uiConfig is enabled on the Account Provider
useAuthModal();
const { const isAuthenticating: booleanisAuthenticating } = function useSignerStatus(override?: AlchemyAccountContextProps): UseSignerStatusResultHook to get the signer status, optionally using an override configuration, useful if you’re building your own login.
useSignerStatus();
function useEffect(effect: React.EffectCallback, deps?: React.DependencyList): voidAccepts a function that contains imperative, possibly effectful code.
useEffect(() => {
if (const isAuthenticating: booleanisAuthenticating) {
const openAuthModal: () => voidopenAuthModal();
}
}, [const openAuthModal: () => voidopenAuthModal, const isAuthenticating: booleanisAuthenticating]);
Embedded auth
The body of the Auth Modal is also exported for you to use directly in your application. This is useful if you don’t want a modal flow for login and want a standalone page using the card.
import React from "react";
import { const AuthCard: (props: AuthCardProps) => JSX.ElementReact component containing an Auth view with configured auth methods and options based on the config passed to the AlchemyAccountProvider
AuthCard } from "@account-kit/react";
export default function function MyLoginPage(): JSX.ElementMyLoginPage() {
return (
<React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div React.HTMLAttributes<HTMLDivElement>.className?: string | undefinedclassName="flex flex-row p-4 bg-white border border-gray-200 rounded-lg">
<const AuthCard: (props: AuthCardProps) => JSX.ElementReact component containing an Auth view with configured auth methods and options based on the config passed to the AlchemyAccountProvider
AuthCard />
</React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div>
);
}
That’s it! The user can now input their credentials and complete login. Once they are authenticated, you can use the useAccount
hook to get the logged in user’s SCA address.
Customize authentication UI
When rendering the authentication component to your users, it’s possible to customize the various sections a user will see as well as the content of the modal.
The easiest way to configure your UI components is using the Demo App.
How does the UI config work?
auth
property accepts asections
objectsections
object is an array of arrays representing the various sections in descending order, each section (element in the outer array) separated by a divider in the UI- each item within a section is an
AuthTypes
objects containing configuration parameters for that authentication method.
The following AuthTypes
can be passed into sections:
This adds an email login to a section. For detailed information on email authentication, see Email OTP and Email Magic Link pages.
Passkey
This adds a passkey login method to a section. For detailed information on passkey authentication, see Passkey Login and Passkey Signup pages.
External wallets
This adds an external wallet login method to a section. This allows users to connect to your app with existing EOAs via browser extension or WalletConnect.
Social
This adds social authentication methods to a section. For detailed information on social authentication, see Social Login and Custom Social Providers pages.
Example
Here’s an example UI configuration which adds 3 sections to the auth modal. The first section contains an email auth, the second section is for passkey login and 2 social auth logins (google and facebook), and the third section is external wallets.
import { type AlchemyAccountsUIConfig = {
auth?: {
addPasskeyOnSignup?: boolean;
header?: React.ReactNode;
hideError?: boolean;
onAuthSuccess?: () => void;
sections: AuthType[][];
hideSignInText?: boolean;
};
illustrationStyle?: "outline" | "linear" | "filled" | "flat" | undefined;
modalBaseClassName?: string;
supportUrl?: string | undefined;
}AlchemyAccountsUIConfig, const createConfig: (props: CreateConfigProps, ui?: AlchemyAccountsUIConfig) => AlchemyAccountsConfigWithUIWraps the createConfig
that is exported from @aa-sdk/core
to allow passing an additional argument, the configuration object for the Auth Components UI (the modal and AuthCard).
createConfig } from "@account-kit/react";
import { const sepolia: Chainsepolia, function alchemy(config: AlchemyTransportConfig): AlchemyTransportCreates an Alchemy transport with the specified configuration options. When sending all traffic to Alchemy, you must pass in one of rpcUrl, apiKey, or jwt. If you want to send Bundler and Paymaster traffic to Alchemy and Node traffic to a different RPC, you must pass in alchemyConnection and nodeRpcUrl.
alchemy } from "@account-kit/infra";
const const uiConfig: AlchemyAccountsUIConfiguiConfig: type AlchemyAccountsUIConfig = {
auth?: {
addPasskeyOnSignup?: boolean;
header?: React.ReactNode;
hideError?: boolean;
onAuthSuccess?: () => void;
sections: AuthType[][];
hideSignInText?: boolean;
};
illustrationStyle?: "outline" | "linear" | "filled" | "flat" | undefined;
modalBaseClassName?: string;
supportUrl?: string | undefined;
}AlchemyAccountsUIConfig = {
illustrationStyle?: "outline" | "linear" | "filled" | "flat" | undefinedillustrationStyle: "outline",
auth?: {
addPasskeyOnSignup?: boolean;
header?: React.ReactNode;
hideError?: boolean;
onAuthSuccess?: () => void;
sections: AuthType[][];
hideSignInText?: boolean;
} | undefinedauth: {
sections: AuthType[][]Each section can contain multiple auth types which will be grouped together and separated by an OR divider
sections: [
[{ type: "email"type: "email" }],
[
{ type: "passkey"type: "passkey" },
{ type: "social"type: "social", authProviderId: KnownAuthProviderauthProviderId: "google", mode: "popup"mode: "popup" },
{ type: "social"type: "social", authProviderId: KnownAuthProviderauthProviderId: "facebook", mode: "popup"mode: "popup" },
],
[
{
type: "external_wallets"type: "external_wallets",
walletConnect?: {
isNewChainsStale?: boolean | undefined;
client?: SignClient | undefined;
projectId: string;
metadata?: Metadata | undefined;
qrModalOptions?: QrModalOptions | undefined;
... 13 more ...;
showQrModal?: boolean | undefined;
} | undefinedwalletConnect: { projectId: stringprojectId: "your-project-id" },
},
],
],
addPasskeyOnSignup?: boolean | undefinedIf this is true, then auth components will prompt users to add a passkey after signing in for the first time
addPasskeyOnSignup: false,
},
};
export const const config: AlchemyAccountsConfigWithUIconfig = function createConfig(props: CreateConfigProps, ui?: AlchemyAccountsUIConfig): AlchemyAccountsConfigWithUIWraps the createConfig
that is exported from @aa-sdk/core
to allow passing an additional argument, the configuration object for the Auth Components UI (the modal and AuthCard).
createConfig(
{
transport: AlchemyTransporttransport: function alchemy(config: AlchemyTransportConfig): AlchemyTransportCreates an Alchemy transport with the specified configuration options. When sending all traffic to Alchemy, you must pass in one of rpcUrl, apiKey, or jwt. If you want to send Bundler and Paymaster traffic to Alchemy and Node traffic to a different RPC, you must pass in alchemyConnection and nodeRpcUrl.
alchemy({ apiKey: stringapiKey: "your-api-key" }),
chain: Chainchain: const sepolia: Chainsepolia,
},
const uiConfig: AlchemyAccountsUIConfiguiConfig,
);
This example would output a modal similar to this image:

Need More Control?
If you need complete control over the user experience, you can implement your own custom UI using Account Kit hooks. See the Authentication with React Hooks page and the individual authentication method pages for detailed implementations.