Abrova
☰ Docs menu · Flutter SDK

Flutter SDK

Abrova Auth for Flutter (abrova_auth). Anonymous, Apple, Google, e-mail and password, magic link and Telegram sign-in with only your public key; the session is kept in secure storage and the user token works in every Abrova SDK.

Flutter 0.1.1Flutter 3.13+Dart 3.0+Last updated: 27 Oct 2026
Client-Safe

Uses the public API key only. Safe to ship in an app

Restored at Start

initialize() loads the saved session with no network call

Secure Storage

Refresh token in the Keychain / Keystore-backed storage

Token Provider

tokenProvider and chatTokenProvider for the other Abrova SDKs

All Methods

Anonymous, Apple, Google, e-mail, magic link, Telegram

Upgrade Guests

linkApple, linkGoogle, linkPassword keep the user id

Abrova Auth Flutter SDK v0.1.1.

This page describes abrova_auth 0.1.1.

Requirements.

Flutter 3.13 or higher. Dart 3.0 or higher. Uses flutter_secure_storage for the session.

Using an AI assistant? Give it this page with Copy page for AI, or all the docs as plain text from /docs/llms.txt. See AI assistants.

Installation#

Packages come from Abrova Center, so pub.dev blocks don't matter. Add the package with the Abrova registry as its hosted source in your pubspec.yaml:

pubspec.yamlYAML
dependencies:
abrova_auth:
  hosted: https://center.abrova.ir/api/packages/abrova/pub
  version: ^0.1.1

Then install it:

bash
flutter pub get

In Abrova Console, turn on Abrova Auth for your project (Settings › Products) and the sign-in methods you want (Abrova Auth › Sign-in methods).

Initialization#

Call AbrovaAuth.initialize once, before runApp, with your public API key (ab_live_...). It restores the session saved on the device without a network call, so currentUser is ready right away.

dart
import 'package:flutter/material.dart';
import 'package:abrova_auth/abrova_auth.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await AbrovaAuth.initialize('ab_live_your_api_key');
  runApp(const MyApp());
}

Then use AbrovaAuth.instance anywhere.

OptionDefaultDescription
apiKey-Your public API key (ab_live_...). Never the server secret.
timeout15 secondsRequest timeout.
refreshMargin2 minutesRenew the access token when less than this is left.
storageSecureAbrovaAuthStorage()Where the session is kept. MemoryAbrovaAuthStorage keeps nothing (tests).

Sign in#

Show only the methods your project has turned on, and sign in only when nobody is signed in yet:

dart
final auth = AbrovaAuth.instance;

final methods = await auth.getMethods();
// methods.anonymous, methods.apple, methods.google, methods.password, methods.magicLink, methods.telegram

if (auth.currentUser == null && methods.anonymous) {
  await auth.signInAnonymously();
}
print(auth.currentUser!.id); // ru_...

signInAnonymously() returns the current user when an anonymous user is already signed in on this device.

Use the user with other Abrova SDKs#

Coming soon. Abrova Sync, Chat, Push, Storage and A/B Testing are coming soon. The calls below show how they will take the Auth user; today, attach the user to Abrova Trace with AbrovaTrace.setUserId(auth.currentUser!.id).

Pass the token provider. The other SDK asks it for a token when it needs one; Abrova Auth renews the token before it expires, and callers at the same time share one renewal.

dart
await AbrovaSync.init(AbrovaSyncConfig(
  apiKey: 'ab_live_your_api_key',
  tokenProvider: AbrovaAuth.instance.tokenProvider, // null while signed out
));

Abrova Chat takes AbrovaAuth.instance.chatTokenProvider (it throws instead of returning null) and currentUser.id as its user id. After a sign-in or sign-out, call the other SDK's refresh method, for example AbrovaSync.refreshUserToken(). See Use with other Abrova products.

Sign-in methods#

Each method has its own page with the Console setup: Anonymous, Apple, Google, E-mail & password, Magic link, Telegram.

E-mail and password

dart
final result = await auth.signUpWithEmail(
  email: email,
  password: password,
  redirectUrl: 'https://example.com/auth/verify', // optional: sends a verification e-mail
);
// result.signedIn is false when the project requires a verified e-mail first.

await auth.signInWithEmail(email: email, password: password);

await auth.sendPasswordReset(email, redirectUrl: 'https://example.com/auth/reset');
await auth.resetPassword(tokenFromLink, newPassword); // ends every session; does not sign in
await auth.verifyEmail(tokenFromLink);
await auth.sendEmailVerification(redirectUrl: 'https://example.com/auth/verify');

The links open your redirectUrl with ?token=.... It must start with one of the link addresses in Abrova Auth › Settings.

Magic link

dart
await auth.sendMagicLink(email, redirectUrl: 'myapp://auth/magic');
// When the app is opened with the link:
await auth.signInWithMagicLink(Uri.parse(link).queryParameters['token']!);

Telegram

dart
final r = await auth.requestTelegramCode('+989121234567');
if (!r.sent && r.botUrl != null) {
  // First time: open r.botUrl so the user starts the bot and shares the number.
}
await auth.verifyTelegramCode('+989121234567', code);

Apple and Google

Run the provider's native plugin with the hashed nonce, and give Abrova the raw one:

dart
final raw = AbrovaAuthNonce.generate();

// sign_in_with_apple
final apple = await SignInWithApple.getAppleIDCredential(
  scopes: [AppleIDAuthorizationScopes.email, AppleIDAuthorizationScopes.fullName],
  nonce: AbrovaAuthNonce.sha256Hex(raw),
);
await auth.signInWithApple(
  idToken: apple.identityToken!,
  rawNonce: raw,
  authorizationCode: apple.authorizationCode, // lets account deletion revoke the Apple sign-in
  name: [apple.givenName, apple.familyName].whereType<String>().join(' '),
);

// google_sign_in 7 — use a new nonce for each sign-in
final rawG = AbrovaAuthNonce.generate();
await GoogleSignIn.instance.initialize(
  serverClientId: 'xxx.apps.googleusercontent.com',
  nonce: AbrovaAuthNonce.sha256Hex(rawG),
);
final account = await GoogleSignIn.instance.authenticate();
await auth.signInWithGoogle(idToken: account.authentication.idToken!, rawNonce: rawG);

Add your bundle IDs and Google client IDs in the Console first. Each nonce works once.

Google sign-in needs a connection to Google, and on Android also Google Play services; some users in Iran have neither. Anonymous, e-mail and password, magic link and Telegram code work without Google, so offer at least one of them as well. See Sign in with Google.

Upgrade an anonymous user#

Linking keeps the user id, so the user's data stays theirs:

dart
try {
  await auth.linkGoogle(idToken: idToken, rawNonce: raw);
  // or linkApple(...), linkPassword(email: ..., password: ...)
} on AbrovaProviderAlreadyLinkedException {
  // This Google account already has a user: offer to sign in with it instead.
}

See Anonymous users & upgrading.

The current user#

dart
auth.currentUser;          // AbrovaAuthUser? — null when signed out
auth.isSignedIn;

auth.authStateChanges.listen((user) {
  // Emits the current user first, then on every sign-in, sign-out and profile change.
});

final me = await auth.getMe(); // fresh from the server
final token = await auth.getToken(); // the access token, if you call your own API with it
FieldTypeDescription
idStringThe user id (ru_...)
anonymousboolTrue until a method is linked
emailVerifiedboolTrue once the e-mail is proved
createdAtDateTime?When the user was created
providersList<String>Linked methods, for example apple, password

Sign out and delete the account#

dart
await auth.signOut();           // this device; never fails
await auth.signOutEverywhere(); // every device
await auth.deleteAccount();     // deletes the user, then signs out

Apple requires apps with sign-in to offer account deletion in the app. See Security & data.

Handle errors#

Every call throws AbrovaAuthException:

dart
try {
  await auth.signInWithEmail(email: email, password: password);
} on AbrovaAuthException catch (e) {
  switch (e.code) {
    case AbrovaAuthErrorCode.invalidCredentials:
      showError('Wrong e-mail or password');
    case AbrovaAuthErrorCode.rateLimited:
      showError('Too many attempts. Try again in ${e.retryAfter?.inSeconds ?? 60} s');
    case AbrovaAuthErrorCode.networkError:
      showError('No connection');
    default:
      showError('Sign-in failed');
  }
}

code is one of AbrovaAuthErrorCode; message is an English hint for developers, not for users. isNetworkError and isSessionEnded help with the common cases. A network error never signs the user out; when the session ends (revoked, expired, account disabled), the SDK signs out and authStateChanges emits null. All codes: Error codes.

Troubleshooting#

METHOD_DISABLED or PRODUCT_DISABLED

Turn on Abrova Auth under Settings › Products and the method under Abrova Auth › Sign-in methods. Use getMethods() to show only the methods that are on.

A new anonymous user on every start

Call initialize() before reading currentUser, and sign in only when currentUser is null.

INVALID_ID_TOKEN from Apple or Google

Check that the bundle ID, Services ID or client ID is in the Console, and that you gave the provider AbrovaAuthNonce.sha256Hex(raw) and Abrova the raw value.

Other Abrova SDKs still act as the previous user

They cache their token. Call their refresh method (for example AbrovaSync.refreshUserToken()) from your authStateChanges listener.

Was this page helpful?
Report a problem