Skip to main content

Authentication

WalletSdk.auth exposes WalletAuth — passkey-based authentication with recovery codes. There are no passwords: registration creates a platform passkey (FIDO2 / WebAuthn), and sign-in performs a passkey assertion.

WalletAuth is UI-agnostic. Every operation returns a typed AuthResult; expected failures (not registered, already registered, user cancelled the passkey sheet) are values, not exceptions. Only transport-level errors throw.

The AuthResult type​

sealed class AuthResult {}

/// Session established (login, register, full recovery).
/// recoveryCodes is non-empty only after registration.
final class AuthSuccess extends AuthResult {
final AuthSession session;
final List<String> recoveryCodes;
}

/// Username-only recovery succeeded; no session — user signs in next.
final class UsernameRecovered extends AuthResult {
final String username;
final String? userId;
}

/// Expected failure. `cancelled` is true when the user dismissed
/// the platform passkey UI.
final class AuthFailure extends AuthResult {
final AuthErrorCode code;
final String? message;
final bool cancelled;
}

AuthSession carries the bearer token, username, optional userId, and issuedAt.

Register​

Creates a new user and a passkey on this device:

final result = await sdk.auth.register(username: '[email protected]');

switch (result) {
case AuthSuccess(:final session, :final recoveryCodes):
// Display recoveryCodes now — this is the only time they are returned.
showRecoveryCodes(recoveryCodes);
onSignedIn(session);
case AuthFailure(:final code, :final cancelled):
if (cancelled) return; // user dismissed the passkey sheet
if (code == AuthErrorCode.userAlreadyRegistered) {
// Offer login instead.
}
case UsernameRecovered():
break; // not returned by register
}
Recovery codes are shown once

AuthSuccess.recoveryCodes is populated only on registration. Persisting or re-displaying them is your app's responsibility — the SDK does not store them.

Sign in​

final result = await sdk.auth.authenticate(username: '[email protected]');

Handle the result exactly as above. Relevant failure codes include usernameNotRegistered, authenticationFailed, authVerificationFailed, and userCredentialsNotFound.

Restore a session on cold start​

Sessions persist in platform secure storage. Skip the passkey ceremony when a valid session exists:

final session = await sdk.auth.restoreSession();
if (session != null) {
onSignedIn(session); // session.token, session.username
} else {
showAuthScreen();
}

Related helpers:

// Token + username without constructing a session object.
final (:token, :username) = await sdk.auth.readStoredCredentials();

// Just the username (e.g. to prefill the login field).
final username = await sdk.auth.readStoredUsername();

// The registered user id for a username, when known.
final userId = await sdk.auth.registeredUserId('[email protected]');

Recovery​

Two scenarios, selected with RecoveryScenario:

ScenarioVerifies codeResets passkeyCreates sessionReturns
userNameOnlyYesNoNoUsernameRecovered
fullRecoveryYesYesYesAuthSuccess

Username-only — the user forgot which email they registered with:

final result = await sdk.auth.recover(
code: enteredRecoveryCode,
scenario: RecoveryScenario.userNameOnly,
);

if (result case UsernameRecovered(:final username)) {
prefillLoginField(username); // user signs in normally afterward
}

Full recovery — the user lost their passkey (new device, cleared credentials). The code is verified, a new passkey is registered, and a session is established:

final result = await sdk.auth.recover(
code: enteredRecoveryCode,
scenario: RecoveryScenario.fullRecovery,
);

if (result case AuthSuccess(:final session)) {
onSignedIn(session);
}

Generate fresh codes for a signed-in user (invalidates prior codes):

final codes = await sdk.auth.generateRecoveryCodes();
showRecoveryCodes(codes);

Logout​

// Clear the auth token but keep the stored username (typical sign-out).
await sdk.auth.logout();

// Clear everything, including the stored username.
await sdk.auth.logout(authTokenOnly: false);

clearStoredSession clears local session state without a backend call:

await sdk.auth.clearStoredSession(); // authTokenOnly: false by default

Error codes​

AuthFailure.code is an AuthErrorCode. The SDK never carries localized strings — map codes to your own copy:

GroupCodes
RegistrationregistrationFailed, registrationAborted, registrationVerificationFailed, userAlreadyRegistered
LoginauthenticationFailed, authenticationAborted, authVerificationFailed, usernameNotRegistered, userCredentialsNotFound
RecoveryrecoveryFailed, recoveryAborted, recoveryCodeVerificationFailed, passkeyResetFailed, recoveryCodesGenerationFailed
LogoutlogoutFailed
Genericunexpected

Observing auth events​

Provide an AuthObserver in WalletSdkOptions to receive lifecycle callbacks for analytics or crash-reporting context — see Configuration.