Abrova
☰ Docs menu · Overview
Coming soon. Abrova Storage is coming soon. This page describes how it will work; it can’t be used yet.

Overview

Abrova Storage is file storage with buckets, public and signed links, on-the-fly image transforms, access rules and a signed Abrova user token, with SDKs for Node.js, Flutter, Web, Android, iOS, React Native, Next.js, and REST.

Last updated: 27 Oct 2026

AbrovaStorage is file storage for your apps: buckets, uploads and downloads, public and signed links, access rules, and on-the-fly image transformations.

Capabilities

  • Uploads — Multipart uploads straight into a bucket.
  • Public and signed links — A public link for files in a public bucket, no key needed; time-limited signed links, made by your server, for private files.
  • Image Transforms — Resize, format conversion and quality settings, also for iPhone and Android HEIC photos; for public files straight from a link such as …?w=600&f=webp.
  • Access Rules — Per-bucket rules for read, write, delete and list, checked against a verified user.

Using an AI assistant? See AI assistants for how to give it these docs.

Available SDKs#

AbrovaStorage ships SDKs for every major platform:

  • Node.js — @abrova/storage-node — server-side: buckets, access rules, signed links, user tokens.
  • Flutter — abrova_storage — Dart SDK for mobile and web.
  • Web — @abrova/storage-web — browser SDK for React/Vue/Svelte/vanilla.
  • Android — ir.abrova:abrova-storage — Kotlin SDK with coroutines.
  • iOS — AbrovaStorage — Swift SDK with async/await + completion handler APIs.
  • React Native — @abrova/storage-react-native — same API as Web SDK.
  • Next.js — combines @abrova/storage-node (server) + @abrova/storage-web (client).
  • REST API — direct HTTP, base URL https://storage.abrova.ir.

Every SDK installs from Abrova Center in two steps: add the Abrova Center registry, then install the package. Each SDK page shows both lines.

What it will cost.

Free every month: 1 GB stored, 5 GB bandwidth and 500 image transforms. Usage above that will cost from your prepaid wallet; the price is set at launch. See Pricing.

Authentication#

AbrovaStorage uses three credentials. Each one proves something different.

CredentialWhere it livesWhat it proves
API key (ab_live_…)Inside your app. Public.Which project the request belongs to.
Server secret (ab_srv_…)Your server only. Never in an app.That a request comes from your backend. Requests with it skip access rules.
User tokenYour app, one per signed-in user.Which user is acting. Access rules see this user.

What each credential can do is fixed; no setting changes it:

ActionFrom an app (API key + user token)From your server (server secret)
Upload, read, list, delete files (incl. deleteMany), image transformsYes, following your access rules. A signed user token is required (401 token_required without one).Yes, access rules skipped. No user token needed.
List and read buckets, get a file's public linkYes, API key alone. No user token needed.Yes
Create, update, delete bucketsNo (403 server_secret_required)Yes
Create, update, delete access rules, apply a templateNo (403 server_secret_required)Yes
Signed download and upload linksNo (403 server_secret_required)Yes

Public links of files in a public bucket (https://storage.abrova.ir/public/…) need no key and no token at all.

Server secret is server-only.

Never put your serverSecret in client-side code, mobile apps, or frontend applications. Use it only on your backend server, from an environment variable.

Sign users in (one token for every Abrova product)#

Every file request from an app carries a signed Abrova user token. This is always required: there is no setting to turn it on or off. Your app cannot say who the user is by itself: the API key it ships with is public, so the server has no reason to believe a user id that comes from a client. Instead, your server mints a short-lived token with the server secret (or Abrova Auth signs the user in), and the SDK sends it on every request. Access rules such as users/{userId}/** and authenticated: true see the user in that token.

Requires the Storage SDK 0.2.1 or newer.

Use Storage SDK 0.2.1 or newer on every platform. An app that doesn't send a user token can't read or write files.

1. Your server mints the token

With the Node.js SDK it is one call:

typescript
import { AbrovaStorage } from '@abrova/storage-node';

const storage = new AbrovaStorage({
  apiKey: process.env.ABROVA_API_KEY!,
  serverSecret: process.env.ABROVA_SERVER_SECRET!, // server only
});

// Your own endpoint, behind your own session check
app.post('/abrova-token', async (req, res) => {
  const { token, expiresAt } = await storage.createUserToken(req.session.userId);
  res.json({ token, expiresAt });
});

Or call the Abrova auth endpoint from any backend:

bash
curl -X POST https://auth.abrova.ir/users/token \
  -H "x-api-key: $ABROVA_API_KEY" \
  -H "x-server-secret: $ABROVA_SERVER_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"userId": "u_4821", "expiresIn": 3600}'

# → { "token": "eyJhbGciOi…", "userId": "u_4821", "expiresIn": 3600, "expiresAt": "2026-10-21T10:00:00.000Z" }

expiresIn is in seconds: 3600 (1 hour) by default, 86400 (24 hours) maximum. It is the same token Abrova Sync, Chat, Push and A/B Testing accept, so one endpoint serves every SDK. Using Abrova Auth? Its sign-in token is this same token: pass its token provider as is, no endpoint of your own needed.

2. The app gives the SDK a token provider

typescript
// Web (React Native is the same)
const storage = new AbrovaStorage({
  apiKey: 'ab_live_xxxxxxxxxxxx',
  tokenProvider: async () => {
    const res = await fetch('/abrova-token', { method: 'POST' });
    return res.ok ? (await res.json()).token : null; // null = no one signed in
  },
});

The SDK sends the token as the x-user-token header, asks the provider before the first request, renews it shortly before it expires, and if the server answers token_expired or token_invalid it asks once more and retries the request once. Call refreshUserToken() when the user signs in or out. Each platform page shows its own syntax.

Without a user token

Without a token, file calls (upload, list, get, download, delete) are not sent and do not fail: they wait. isAwaitingUserToken is true meanwhile, and onAwaitingUserToken tells you when calls start waiting, so you can show your sign-in screen. Once the provider returns a token (call refreshUserToken()) or you call setUserToken(token), the waiting calls go on in order. Set userTokenWaitTimeout to make a waiting call fail with token_required instead. Bucket reads (listBuckets, getBucket, getBucketByName) and public links never wait.

A file call made before sign-in finishes only after sign-in, so don't wait for it in code the user is waiting on (a button handler, a startup check). With Abrova Auth, the sign-in method you use (for example Anonymous) must be on in Abrova Auth › Sign-in methods; if it is off, sign-in fails with METHOD_DISABLED and file calls wait without an error.

401 codeMeaningWhat the SDK does
token_requiredThe request had no user token.Waits for a token (or fails after userTokenWaitTimeout).
token_expiredThe token has expired.Asks the provider again and retries once.
token_invalidBad signature, wrong project, or not an Abrova user token.Asks the provider again and retries once; then throws.

Defaults to keep

  • Leave userTokenWaitTimeout unset: by default file calls wait until a user signs in. Set it only when a screen waits for the answer and can send the user to sign-in.
  • Don't add your own timeouts or retries around file calls for a missing user. Show sign-in instead; the waiting calls go on by themselves.
  • While developing, log from onAwaitingUserToken, so a call that waits for a user is easy to spot.

Errors#

Every refused request answers JSON with a statusCode, a message you can show, and a code you can switch on, for example { "statusCode": 400, "code": "type_not_allowed", "message": "…" }. The SDKs expose code as constants (StorageErrorCode). Answers contain only the documented fields of a file, bucket or rule — see REST API for the full list of codes.

Bucket Visibility#

When creating a bucket, you can choose between two visibility modes that control how files can be accessed.

  • private (default) — Files are read through the API (with your API key, following your access rules) or through a signed link your server makes. Best for user documents, invoices, receipts, contracts, personal audio recordings, and sensitive data.
  • public — Each file also has a public link that needs no key. Anyone with the link can view or download the file. Best for user avatars, profile pictures, product images, public assets, and shared content.

Showing a file in an image or a page

For a file in a public bucket, use its public link. It needs no key, token or header, so it goes straight into <img src>, srcset, Image.network(url) or an e-mail. Add image options to get a resized or converted image:

dart
// Public bucket: the public link, optionally with image options
final link = await storage.getPublicUrl(fileId);
// https://storage.abrova.ir/public/<bucketId>/<path>
final thumb = await storage.getPublicUrl(fileId,
    transforms: const ImageTransforms(width: 600, format: 'webp'));
// https://storage.abrova.ir/public/<bucketId>/<path>?w=600&f=webp
Image.network(thumb);

// Private bucket: download the bytes in the app...
final bytes = await storage.download(fileId);
Image.memory(bytes);

// ...or have your server make a time-limited signed link
// (Node.js SDK, server secret): await storage.getSignedUrl(fileId, { expiresIn: 600 })

getPublicUrl() fails with 403 for a file in a private bucket, and a /public/… link of a private file answers 404. getUrl(), getDownloadUrl() and getTransformUrl() return API addresses that need the x-api-key and x-user-token headers, so don't put them in a plain <img src>. See Image Transforms.

Visibility is mutable.

You can change a bucket's visibility at any time from the dashboard. When a bucket becomes private, its public links stop working, but browsers and other caches that already cached a file may keep showing it for up to a day. Don't rely on it to revoke a file someone already has. Signed links keep working until they expire.

Was this page helpful?
Report a problem