Install @teamhanko/hanko-elements
Once you’ve initialized your React app, installing hanko-elements provides you with access to the prebuilt components: hanko-auth
and hanko-profile
.
Add the Hanko API URL
Retrieve the API URL from the Hanko console and place it in your .env file.
Create React App React with Vite REACT_APP_HANKO_API_URL = https://f4****-4802-49ad-8e0b-3d3****ab32.hanko.io
If you are self-hosting you need to provide the URL of your running Hanko
backend.
Add <hanko-auth>
component
The <hanko-auth>
web component adds a login interface to your app. Begin by importing the register
function from @teamhanko/hanko-elements
into your React component. Call it with the Hanko API URL as an argument to register <hanko-auth>
with the browser’s CustomElementRegistry . Once done, include it in your JSX.
Create React App React with Vite import { useEffect } from "react" ;
import { register } from "@teamhanko/hanko-elements" ;
const hankoApi = process. env . REACT_APP_HANKO_API_URL ;
export default function HankoAuth ( ) {
useEffect ( ( ) => {
register ( hankoApi) . catch ( ( error ) => {
} ) ;
} , [ ] ) ;
return < hanko-auth /> ;
}
Define event callbacks
The Hanko client from @teamhanko/hanko-elements
lets you “listen” for specific events . It simplifies the process of subscribing to events, such as user logins.
Create React App React with Vite import { useEffect, useCallback, useMemo } from "react" ;
import { useNavigate } from "react-router-dom" ;
import { register, Hanko } from "@teamhanko/hanko-elements" ;
const hankoApi = process. env . REACT_APP_HANKO_API_URL ;
export default function HankoAuth ( ) {
const navigate = useNavigate ( ) ;
const hanko = useMemo ( ( ) => new Hanko ( hankoApi) , [ ] ) ;
const redirectAfterLogin = useCallback ( ( ) => {
navigate ( "/dashboard" ) ;
} , [ navigate] ) ;
useEffect (
( ) =>
hanko. onSessionCreated ( ( ) => {
redirectAfterLogin ( ) ;
} ) ,
[ hanko, redirectAfterLogin]
) ;
useEffect ( ( ) => {
register ( hankoApi) . catch ( ( error ) => {
} ) ;
} , [ ] ) ;
return < hanko-auth /> ;
}
By now, your sign-up and sign-in features should be working. You should see an interface similar to this 👇
Add <hanko-profile>
component
The <hanko-profile>
component provides an interface, where users can manage their email addresses and passkeys.
Create React App React with Vite components/HankoProfile.tsx
import { useEffect } from "react" ;
import { register } from "@teamhanko/hanko-elements" ;
const hankoApi = process. env . REACT_APP_HANKO_API_URL ;
export default function HankoProfile ( ) {
useEffect ( ( ) => {
register ( hankoApi) . catch ( ( error ) => {
} ) ;
} , [ ] ) ;
return < hanko-profile /> ;
}
It should look like this 👇
Implement logout functionality
You can use @teamhanko/hanko-elements
to easily manage user logouts. Below, we make a logout button component that you can use anywhere.
Create React App React with Vite components/LogoutButton.tsx
import React , { useState, useEffect } from "react" ;
import { useNavigate } from "react-router-dom" ;
import { Hanko } from "@teamhanko/hanko-elements" ;
const hankoApi = process. env . REACT_APP_HANKO_API_URL ;
function LogoutBtn ( ) {
const navigate = useNavigate ( ) ;
const [ hanko, setHanko] = useState< Hanko > ();
useEffect ( ( ) => {
import ( "@teamhanko/hanko-elements" ) . then ( ( { Hanko } ) =>
setHanko ( new Hanko ( hankoApi ?? "" ) )
) ;
} , [ ] ) ;
const logout = async ( ) => {
try {
await hanko?. user. logout ( ) ;
navigate ( "/login" ) ;
} catch ( error) {
console . error ( "Error during logout:" , error) ;
}
} ;
return < button onClick = { logout} > Logout </ button> ;
}
export default LogoutBtn ;
Customize component styles
You can customize the appearance of hanko-auth
and hanko-profile
components using CSS variables and parts. Refer to our customization guide .
Getting User and Session Data
Client Side
We will create two custom hooks to fetch the current user’s data and session data using @teamhanko/hanko-elements
. The useUserData
hook leverages the hanko.user.getCurrent()
method to retrieve the currently logged-in user’s data.
On the other hand, the useSessionData
hook uses the hanko.session.isValid()
and hanko.session.get()
methods to validate and fetch the current session data.
useUserData useSessionData import { useState, useEffect, useMemo } from "react" ;
import { Hanko } from "@teamhanko/hanko-elements" ;
const hankoApi = process. env . REACT_APP_HANKO_API_URL ;
interface HankoUser {
id: string ;
email: string ;
loading: boolean ;
error: string | null ;
}
export function useUserData ( ) : HankoUser {
const hanko = useMemo ( ( ) => new Hanko ( hankoApi) , [ ] ) ;
const [ userState, setUserState] = useState < HankoUser> ( {
id: "" ,
email: "" ,
loading: true ,
error: null ,
} ) ;
useEffect ( ( ) => {
hanko?. user
. getCurrent ( )
. then ( ( { id, email } ) => {
setUserState ( { id, email, loading: false , error: null } ) ;
} )
. catch ( ( error) => {
setUserState ( ( prevState) => ( { ... prevState, loading: false , error } ) ) ;
} ) ;
} , [ hanko] ) ;
return userState;
}
This is how you can use them according to your needs.
import { useUserData } from "@/hooks/useUserData" ;
import { useSessionData } from "@/hooks/useSessionData" ;
const UserData = ( ) => {
const { id, email, loading: userDataLoading, error: userDataError } = useUserData ( ) ;
const { userID, jwt, isValid, loading: sessionDataLoading, error: sessionDataError } = useSessionData ( ) ;
if ( userDataLoading) {
return < div> Loading... </ div> ;
}
return (
< div>
< div> User id: { id} </ div>
< div> User email: { email} </ div>
</ div>
) ;
} ;
export default UserData ;
You might get "r" is read-only
error after you deploy a CRA (Create React App). To fix it you’ll need to add @babel/core
as a dependency in your project. You can do this by running the following command:
Authenticate backend requests
To authenticate requests on your backend with Hanko, refer to our backend guide .
Try it yourself
React example (Vite) It uses Express.js for the backend, full source code available on our GitHub.