Authentication
Core SDK — Authentication
This page explains OAuth sign-in and session handling for the JavaScript SDK.
Login provider
Choose a specific provider or let the user pick from a selector modal:
// Provider selector modal
const result = await sdk.signIn()
// Direct Google login
const result = await sdk.signIn({ provider: 'google' })
// Direct Apple login
const result = await sdk.signIn({ provider: 'apple' })Session lifecycle
initialize()
initialize()Try restoring a stored session on page load:
const restored = await sdk.initialize() // AuthResult | null
// Or specify which wallet to use on restore
const restored = await sdk.initialize({ preferredWalletIndex: 1 })
// ... or by address
const restored = await sdk.initialize({ preferredWalletAddress: '0xYourWallet...' })whenReady()
whenReady()Wait until initialization has finished (avoids racing isAuthenticated() against an in-flight initialize()):
const ready = await sdk.whenReady() // true once initialize() completed, false if never startedisAuthenticated() / isLoggedIn()
isAuthenticated() / isLoggedIn()Fast local check only (no refresh call):
const loggedIn = sdk.isAuthenticated() // boolean
const loggedIn = sdk.isLoggedIn() // aliasensureLoggedIn()
ensureLoggedIn()Ensures a usable session now (includes restore/refresh attempt):
const ok = await sdk.ensureLoggedIn() // booleanIf the session is expired but a refresh token is valid, it is restored automatically. Returns false if login is required.
Sign-in / Sign-out
// Open OAuth (popup)
const auth = await sdk.signIn()
if (auth.success) {
console.log('Address:', auth.address)
console.log('User:', auth.user)
}
// Clear local session
await sdk.signOut()User info
const userInfo = await sdk.getUserInfo()
console.log(userInfo.id) // JWT sub
console.log(userInfo.email) // email (if available)
console.log(userInfo.loginType) // 'google' | 'apple'
console.log(userInfo.addresses) // wallet address arraySign in + wallet creation (one-step)
signInWithCreate() performs sign-in, wallet creation, and migration in a single call. It returns the full address list along with the AuthResult.
const result = await sdk.signInWithCreate()
if (result.success) {
console.log('Address:', result.address)
console.log('All addresses:', result.addresses)
// result.addresses → [{ address: '0x...', index: 0, name?: 'My Wallet' }]
}If the user has no wallet yet, one is created automatically. If a CROSSx wallet backup is detected, migration is triggered internally.
Automatic wallet selection (2+ wallets)
When the user has two or more wallets, signInWithCreate() automatically displays the wallet selector modal after sign-in. The selected wallet is returned as result.address.
| Wallet count | Behavior |
|---|---|
| 0 | Creates a new wallet, no selector shown |
| 1 | Returns the wallet directly, no selector shown |
| 2+ | Shows selectWallet() modal → selected wallet becomes result.address |
If the user cancels the selector, the default wallet (index 0) is used.
To skip the selector, pass preferredWalletAddress (SignInWithCreateOptions) — if the address exists in the user's wallet list, it is selected without showing the modal:
const result = await sdk.signInWithCreate({
provider: 'google',
preferredWalletAddress: '0xKnownWallet...',
})const result = await sdk.signInWithCreate()
if (result.success) {
// result.address — the wallet selected by the user (or default if only one)
// result.addresses — full wallet list regardless of selection
console.log('Selected wallet:', result.address)
console.log('All wallets:', result.addresses.length)
}The SDK updates
currentAddressand emitsaddressChangedwhen a wallet is selected duringsignInWithCreate(). This differs from standaloneselectWallet(), which does not update SDK state.
JWT authentication
For apps with their own backend authentication, you can sign in using a pre-obtained JWT token:
// Sign in with JWT from your backend
const auth = await sdk.signInWithJWT(accessToken, refreshToken)
if (auth.success) {
console.log('Address:', auth.address)
}| Parameter | Type | Required | Description |
|---|---|---|---|
accessToken | string | Yes | JWT access token from your backend |
refreshToken | string? | No | Optional refresh token |
This is useful when you handle OAuth on the server side and pass the resulting JWT to the SDK.
External OAuth token sign-in
When the OAuth flow happens outside the SDK — for example a native host app completes Google/Apple login and hands the Firebase ID token to the WebView via deeplink — use signInWithOAuthToken(). It behaves like signInWithCreate() after authentication (creates a wallet if needed, shows the wallet selector for 2+ wallets):
const result = await sdk.signInWithOAuthToken(firebaseTokenFromDeeplink)
if (result.success) {
console.log('Address:', result.address)
}The resulting authChanged event carries source: 'external' so subscribers can distinguish it from interactive sign-ins. The parseOAuthDeeplink export helps extract the token from an OAuth deeplink in React Native WebView setups.
Session expiry recovery
When both the access and refresh tokens are invalid, SDK calls throw SESSION_EXPIRED. Use signInAgain() to re-authenticate the same account:
const auth = await sdk.signInAgain() // AuthResult
if (!auth.success) {
// user signed in with a different account or cancelled — treat as logged out
}signInAgain() opens OAuth again and verifies the account matches the previous session. If a different account is used, the SDK signs it out and asks the user to retry with the original account.
Migration handling
When a CROSSx wallet backup is detected during sign-in, the SDK automatically triggers a migration flow:
const result = await sdk.signIn()
if (result.needsMigration) {
// Call createWallet() to trigger migration UI
await sdk.createWallet()
}
// Or use signInWithCreate() to handle this automatically
const result = await sdk.signInWithCreate()Event-driven auth state
The SDK emits events when auth state changes. This is useful for reactive frameworks:
const unsub = sdk.on('authChanged', (event) => {
console.log('Authenticated:', event.isAuthenticated)
console.log('Address:', event.address)
console.log('User ID:', event.userId)
})
// Cleanup
unsub()Recommended app flow
- Page load: call
initialize() - Before protected action: call
ensureLoggedIn() - User login action: call
signIn()orsignInWithCreate() - User logout action: call
signOut()
Updated 2 days ago