Choosing an authentication method
For most applications, enable email authentication and optionally offer passkeys. If you use passkeys as the primary authentication method, require users to enroll an email address as a backup before they fund their wallet.
Accounts and identity
Rules that shape your login screens:- Email and phone number identify the account. The first sign up with an email address or phone number creates an account. Future logins with that same contact return the user to the same wallet. If the same person signs up separately with email and SMS, Rain treats them as separate accounts unless one contact is added to the existing account.
- Accounts are not automatically merged. If a user creates two accounts, they will have two separate wallets. Returning users should use Log in or Add a passkey rather than Create account.
- Passkey sign up creates an account without a contact method.
signUpWithPasskeycreates an account whose initial authentication method is the passkey. Prompt the user to add an email address as a backup immediately after sign up before funding the wallet. See Backup and recovery. - The same account works across supported platforms. A user who signs up on iOS can log in on Android with an authentication method already associated with their account and access the same wallet.
Logging in with a one-time code
1
Send the code
Call Phone numbers must be in international (E.164) format. Validation failures throw
sendLoginCode with the contact. Rain sends a 6-digit code. Calling again for the same contact replaces the pending code, which is your Resend button.RAIN_102 before any request is made.2
Confirm the code
Call
confirmLoginCode with what the user typed. Success logs the user in; on a first login it also creates the wallet. A wrong code throws RAIN_203 and leaves the pending challenge intact, so the user retries without a new code. Codes expire after 5 minutes and lock after 3 wrong attempts; after either, send a new one.Logging in with a passkey
Passkeys are available on iOS and Android. A passkey created on one platform is bound to your domain and your app, so the same account can hold passkeys from both.1
Set up your domain
Choose a domain you’ll keep. Passkeys are scoped to it: users’ passkeys won’t work if you change it later, and the same account can hold passkeys from more than one domain. Rain runs no shared domain; you host the association files yourself.The domain is applied once per app launch. Without it, every passkey call throws
- iOS: Host
https://<domain>/.well-known/apple-app-site-associationlisting your app underwebcredentials, and addwebcredentials:<domain>to your app’s Associated Domains. - Android: Host
https://<domain>/.well-known/assetlinks.jsonwith two statements: one for the site itself grantingdelegate_permission/common.get_login_creds, and anandroid_appstatement granting bothdelegate_permission/common.handle_all_urlsanddelegate_permission/common.get_login_credsthat lists your package name and the SHA-256 fingerprint of every certificate that signs your app (debug, upload, and Play App Signing). The device refuses a file that carries the app statement alone.
RAIN_102. On Android, a value that isn’t a registrable domain of at least two labels (a scheme, port, path, or localhost) throws RAIN_102 from the constructor.2
Offer the right action
Three calls cover the flows. On iOS each takes an Show Sign in with passkey and Create account as distinct choices, and put Add a passkey inside the app for users who logged in with a code. Call
anchor, the window the system sheet presents from; on Android each takes the foreground Activity and suspends until the sheet closes.logout() before starting a passkey sign-up while a session is live: the SDK refuses with RAIN_102 otherwise. On iOS the same applies to a passkey login over a live passkey session; on Android a passkey login replaces the current session. A dismissed sheet throws RAIN_401 and leaves the current session untouched.3
Ask for a backup contact
A passkey-only account is one lost device away from being unreachable if the passkey isn’t synced. After sign-up, collect an email address and verify it with
sendContactVerificationCode and confirmContactVerification. The verified contact becomes a login method for the account. Details in Backup and recovery.Sessions
A successful login stores a session in the device’s secure storage. The SDK manages it from there:- Restore. On launch,
awaitSessionRestore()waits (up to 5 seconds) for the stored session to load. ThenhasActiveSession()tells you whether to show the login screen. - Observe.
authStatereportsloading,authenticated, orunauthenticated; bind your login gate to it. A finersessionStateaddsactive(expiresAt)andexpiredif you want to show a countdown or pre-empt expiry. - Refresh. Sessions refresh automatically ahead of expiry (
RainWalletSessionPolicy: 60-second buffer, two transient retries with backoff). Reads are retried on transient failures; sends never are. CallrefreshSession()to force one, for example when the app returns to the foreground. - Expiry. When a session can’t be refreshed, or the user logged in on another device, the SDK fires
onSessionExpiredonce and calls throwRAIN_201until the user logs in again. Ending a session withlogout()doesn’t fire the hook. - One device at a time. A login ends the user’s sessions on other devices. The signed-out device finds out on its next call.
What’s next
Wallet creation
What a first login creates, and what to do with the addresses.
Backup and recovery
Keep every account reachable.