Overview
Staxiq uses @stacks/connect for wallet authentication, providing seamless integration with popular Stacks wallets like Leather, Xverse, and Asigna. Authentication persists across sessions using the UserSession API.
Authentication Flow
The authentication system is managed through the useWallet hook, which handles:
Wallet connection prompts
Session persistence
Network detection (testnet/mainnet)
Address extraction
Disconnection and cleanup
Initialize App Config
Configure app permissions and create a UserSession instance. import { AppConfig , UserSession } from '@stacks/connect' ;
const appConfig = new AppConfig ([ 'store_write' , 'publish_data' ]);
const userSession = new UserSession ({ appConfig });
Trigger Authentication
Call the authenticate function with app details and callbacks. import { authenticate } from '@stacks/connect' ;
authenticate ({
userSession ,
appDetails: {
name: 'Staxiq' ,
icon: window . location . origin + '/favicon.ico' ,
},
onFinish : ( payload ) => {
const userData = payload . userSession . loadUserData ();
const address = userData ?. profile ?. stxAddress ?. mainnet ;
// Handle successful connection
},
onCancel : () => {
// Handle user cancellation
},
});
Check Existing Session
On app load, check if user is already authenticated. if ( userSession . isUserSignedIn ()) {
const userData = userSession . loadUserData ();
const address = userData ?. profile ?. stxAddress ?. mainnet ;
// User is already connected
}
Handle Disconnection
Sign out and clear session data. userSession . signUserOut ();
window . location . reload (); // Refresh to reset app state
Using the useWallet Hook
The recommended way to handle authentication is through the useWallet hook:
import { useWallet } from './hooks/useWallet' ;
function WalletButton () {
const {
connected ,
address ,
shortAddress ,
connectWallet ,
disconnectWallet ,
loading
} = useWallet ();
if ( loading ) {
return < button disabled > Connecting... </ button > ;
}
if ( connected ) {
return (
< div >
< span > Connected: { shortAddress ( address ) } </ span >
< button onClick = { disconnectWallet } > Disconnect </ button >
</ div >
);
}
return < button onClick = { connectWallet } > Connect Wallet </ button > ;
}
View full useWallet documentation →
Network Detection
Staxiq automatically detects the correct network based on the user’s address:
Addresses starting with ST use testnet
Addresses starting with SP use mainnet
const getStxAddress = ( userData ) => {
return network === 'testnet'
? userData ?. profile ?. stxAddress ?. testnet
: userData ?. profile ?. stxAddress ?. mainnet ;
};
Session Persistence
User sessions are automatically persisted in browser storage. When users return to your app:
useEffect (() => {
if ( userSession . isUserSignedIn ()) {
const userData = userSession . loadUserData ();
const addr = getStxAddress ( userData );
if ( addr ) {
setAddress ( addr );
setConnected ( true );
}
}
}, []);
App Configuration
Required Permissions
Allows the app to write to Gaia storage (user’s decentralized storage)
Enables publishing data to the blockchain
App Details
Application name shown in wallet connection prompt
App icon URL displayed during authentication (must be absolute URL)
User Data Structure
After successful authentication, the user data object contains:
User profile information Stacks addresses for different networks Mainnet address (starts with SP)
Testnet address (starts with ST)
BNS username if registered
Error Handling
Handle authentication errors gracefully:
try {
await authenticate ({
userSession ,
appDetails ,
onFinish : ( payload ) => {
console . log ( 'Authentication successful' );
console . log ( 'isSignedIn:' , payload . userSession . isUserSignedIn ());
},
onCancel : () => {
console . log ( 'User cancelled authentication' );
setLoading ( false );
},
});
} catch ( error ) {
console . error ( 'Authentication error:' , error );
setLoading ( false );
}
Logout Flow
Properly clean up user sessions on logout:
function disconnectWallet () {
try {
userSession . signUserOut ();
} catch ( err ) {
console . error ( 'Logout error:' , err );
}
setConnected ( false );
setAddress ( null );
window . location . reload ();
}
The page reload ensures all components and contexts are reset to their unauthenticated state.
Utility function to display shortened addresses:
function shortAddress ( addr ) {
if ( ! addr ) return '' ;
return ` ${ addr . slice ( 0 , 5 ) } ... ${ addr . slice ( - 4 ) } ` ;
}
// Example: "SP2H8...9ABC"
Complete Example
Component Usage
Manual Implementation
import { useWallet } from './hooks/useWallet' ;
import { useNetwork } from './context/NetworkContext' ;
function App () {
const { connected , address , connectWallet , disconnectWallet } = useWallet ();
const { network } = useNetwork ();
return (
< div >
< header >
< h1 > Staxiq - Bitcoin DeFi Copilot </ h1 >
{ connected ? (
< div >
< span > Network: { network } </ span >
< span > Address: { address } </ span >
< button onClick = { disconnectWallet } > Disconnect </ button >
</ div >
) : (
< button onClick = { connectWallet } > Connect Wallet </ button >
) }
</ header >
{ connected && (
< main >
< Dashboard address = { address } />
</ main >
) }
</ div >
);
}
Best Practices
Loading States Always show loading indicators during wallet connection to improve UX
Error Recovery Provide clear error messages and retry options for failed connections
Session Checking Check for existing sessions on app load to auto-reconnect users
Clean Logout Always call signUserOut() and reload to prevent state inconsistencies