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:

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:

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.

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.Element
MyPage
() {
const {
const openAuthModal: () => void
openAuthModal
} =
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> | undefined
onClick
={
const openAuthModal: () => void
openAuthModal
}>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) => UseSignerStatusResult

Hook 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): void

Accepts a function that contains imperative, possibly effectful code.

useEffect
} from "react";
const {
const openAuthModal: () => void
openAuthModal
} =
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: boolean
isAuthenticating
} =
function useSignerStatus(override?: AlchemyAccountContextProps): UseSignerStatusResult

Hook 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): void

Accepts a function that contains imperative, possibly effectful code.

useEffect
(() => {
if (
const isAuthenticating: boolean
isAuthenticating
) {
const openAuthModal: () => void
openAuthModal
();
} }, [
const openAuthModal: () => void
openAuthModal
,
const isAuthenticating: boolean
isAuthenticating
]);

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.Element

React 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.Element
MyLoginPage
() {
return ( <
React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
React.HTMLAttributes<HTMLDivElement>.className?: string | undefined
className
="flex flex-row p-4 bg-white border border-gray-200 rounded-lg">
<
const AuthCard: (props: AuthCardProps) => JSX.Element

React 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 a sections object
  • sections 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:

Email

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.

1type ExternalWalletsAuthType = {
2 type: "external_wallets";
3 // if this is undefined, wallet connect will not be displayed
4 walletConnect?: WalletConnectParameters;
5};

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) => AlchemyAccountsConfigWithUI

Wraps 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: Chain
sepolia
,
function alchemy(config: AlchemyTransportConfig): AlchemyTransport

Creates 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: AlchemyAccountsUIConfig
uiConfig
:
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" | undefined
illustrationStyle
: "outline",
auth?: { addPasskeyOnSignup?: boolean; header?: React.ReactNode; hideError?: boolean; onAuthSuccess?: () => void; sections: AuthType[][]; hideSignInText?: boolean; } | undefined
auth
: {
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: KnownAuthProvider
authProviderId
: "google",
mode: "popup"
mode
: "popup" },
{
type: "social"
type
: "social",
authProviderId: KnownAuthProvider
authProviderId
: "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; } | undefined
walletConnect
: {
projectId: string
projectId
: "your-project-id" },
}, ], ],
addPasskeyOnSignup?: boolean | undefined

If 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: AlchemyAccountsConfigWithUI
config
=
function createConfig(props: CreateConfigProps, ui?: AlchemyAccountsUIConfig): AlchemyAccountsConfigWithUI

Wraps 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: AlchemyTransport
transport
:
function alchemy(config: AlchemyTransportConfig): AlchemyTransport

Creates 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: string
apiKey
: "your-api-key" }),
chain: Chain
chain
:
const sepolia: Chain
sepolia
,
},
const uiConfig: AlchemyAccountsUIConfig
uiConfig
,
);

This example would output a modal similar to this image:

Example custom UI config

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.