ورود مهمان و ارتقای بعدی
پیش از شروع
- ناشناس و ایمیل در کنسول روشن باشند
A sign-in wall on the first screen loses users. With Abrova Auth the app signs each new user in as an anonymous guest with no screen at all. The guest has a real user id from the start, so everything you store under it is theirs. When they decide to sign up, you link an e-mail and password to that same user: the id doesn't change and nothing has to be moved.
Turn on Abrova Auth and the two methods#
In Abrova Console:
- Settings › Products: turn on Abrova Auth.
- Abrova Auth › Sign-in methods: turn on Anonymous and E-mail and password. For e-mail, set the shortest password (8 to 128 characters, default 8) and whether users need a verified e-mail before they can sign in.
- Copy the public key (
ab_live_…) from Project settings → Keys. Abrova Auth needs nothing else: no server, no server secret.
Install the SDK#
Flutter
Add the package with the Abrova registry as its hosted source, then run flutter pub get:
# pubspec.yaml
dependencies:
abrova_auth:
hosted: https://center.abrova.ir/api/packages/abrova/pub
version: ^0.1.1Web
Point the @abrova scope at Abrova Center in .npmrc, then install:
# .npmrc @abrova:registry=https://center.abrova.ir/api/packages/abrova/npm/
npm install @abrova/auth-web
Sign the guest in at first launch#
Sign in anonymously only when nobody is signed in yet. The SDK keeps the session, so the same guest comes back on the next launch; calling signInAnonymously() on every start would create a new user each time.
Flutter
import 'package:flutter/material.dart';
import 'package:abrova_auth/abrova_auth.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// Restores the saved session from secure storage, without a network call.
await AbrovaAuth.initialize('ab_live_your_api_key');
final auth = AbrovaAuth.instance;
if (auth.currentUser == null) {
await auth.signInAnonymously();
}
runApp(const MyApp());
}Web
On the web the session is kept in memory by default, so a guest would be lost on every reload. Keep it in localStorage for this flow, and wait for ready() before you check:
import { createAbrovaAuth, localStorageStorage } from '@abrova/auth-web';
export const auth = createAbrovaAuth({
apiKey: 'ab_live_your_api_key',
storage: localStorageStorage(), // the guest survives a reload
});
export async function startSession() {
await auth.ready(); // the stored session (if any) is loaded
if (!auth.isSignedIn) {
await auth.signInAnonymously();
}
return auth.currentUserId; // ru_…
}localStorage. Use it only with a strict Content Security Policy and no untrusted scripts. See Staying signed in.Store the user's data under this id from now on (currentUser.id on Flutter, currentUserId on the web). If you also use Abrova Trace, attach the id to errors: see Attach the signed-in user to errors.
Show who is a guest#
Offer "Create an account" only to guests. The user's anonymous field is true until a method is linked, and your auth listener hears about every change:
Flutter
StreamBuilder<AbrovaAuthUser?>(
stream: AbrovaAuth.instance.authStateChanges, // current user first, then every change
builder: (context, snapshot) {
final user = snapshot.data;
if (user == null) return const SizedBox.shrink();
return user.anonymous
? TextButton(onPressed: openSignUp, child: const Text('Create an account'))
: Text('Signed in as ${user.id}');
},
)Web
const me = await auth.getMe(); // { id, anonymous, emailVerified, createdAt, providers }
showSignUpButton(me.anonymous); // your codeUpgrade: link an e-mail and password#
When the guest signs up, link the e-mail and password to the signed-in guest. Don't call signUpWithEmail here: that creates a new user and leaves the guest's data behind.
Flutter
Future<void> upgrade(String email, String password) async {
final auth = AbrovaAuth.instance;
try {
await auth.linkPassword(email: email, password: password);
// Same user id. currentUser.anonymous is now false.
// Optional: ask them to confirm the address.
await auth.sendEmailVerification(redirectUrl: 'https://example.com/auth/verify');
} on AbrovaAuthException catch (e) {
switch (e.code) {
case AbrovaAuthErrorCode.emailTaken:
showError('This e-mail already has an account. Sign in instead?');
case AbrovaAuthErrorCode.weakPassword:
showError('Choose a longer, less common password.');
case AbrovaAuthErrorCode.networkError:
showError('No connection. Try again.');
default:
showError('Could not create the account.');
}
}
}Web
import { isAbrovaAuthError } from '@abrova/auth-web';
export async function upgrade(email: string, password: string) {
try {
await auth.linkPassword({ email, password }); // same user id
await auth.sendEmailVerification({ redirectUrl: 'https://example.com/auth/verify' });
} catch (e) {
if (isAbrovaAuthError(e) && e.code === 'EMAIL_TAKEN') showError('This e-mail already has an account.');
else if (isAbrovaAuthError(e) && e.code === 'WEAK_PASSWORD') showError('Choose a longer password.');
else throw e;
}
}The verification link opens your redirectUrl with ?token=…; pass the token to verifyEmail. The redirectUrl must start with one of the link addresses under Abrova Auth › Settings. Linking also starts a fresh session, which the SDK takes over by itself.
When the e-mail already has an account#
EMAIL_TAKEN means the person signed up before, on another device or before reinstalling. Nothing is merged on its own: two users' data is never combined behind your back. What most apps do:
- Tell the user this account already exists and offer to sign in.
- If the guest has data worth keeping, copy it to the other account in your app first (or let the user discard it).
- Sign in with
signInWithEmail. This replaces the guest on this device: the guest is not deleted, but no device holds its session any more, so it can't be reached again.
await AbrovaAuth.instance.signInWithEmail(email: email, password: password);
Guests that never come back are removed after 90 days without a sign-in (7 to 3,650 days, under Abrova Auth › Settings › Anonymous users). Users who linked a method are never removed this way.
Check that it worked#
- Start the app: in Abrova Console → Abrova Auth › Users a new user appears with the method anonymous.
- Restart the app (or reload the page): no second user appears.
- Sign up in the app: the same user now lists password among its methods, and its id is unchanged.
Troubleshooting#
A new guest on every start
Flutter: call AbrovaAuth.initialize before reading currentUser, and sign in only when it is null. Web: pass storage: localStorageStorage() and await auth.ready() before checking isSignedIn; the default memory storage forgets the session on reload.
METHOD_DISABLED or PRODUCT_DISABLED
Turn on Abrova Auth under Settings › Products, and Anonymous and E-mail and password under Abrova Auth › Sign-in methods.
RATE_LIMITED on signInAnonymously
Too many new guests from one address, or the project's daily limit (200 new anonymous users a day, or your own lower limit) is reached. Wait for retryAfter (Flutter) or retryAfterSec (web). Existing users are not affected.
EMAIL_TAKEN when linking
Another user already has this e-mail. Offer sign-in or a password reset, as in step 6.
Signing in later on another device fails with EMAIL_NOT_VERIFIED
Your project requires a verified e-mail. Send the verification e-mail after linking (step 5) and ask the user to open it.
MAU_LIMIT for new users
This month's 1,000 free monthly active users are used up and the wallet has no balance. Top up the wallet in Abrova Console to let new users in.
- اگر ایمیل مال کاربر دیگری است، تعارض را نشان دهید — ادغام بیصدا وجود ندارد.
- فقط وقتی کسی وارد نشده ناشناس وارد کنید، وگرنه هر اجرا یک مهمان تازه میسازد.
- در وب نشست بهطور پیشفرض در حافظهی موقت است: مهمانها را با localStorageStorage() نگه دارید.
بعدی: شروع سریع Auth