---
title: "claimهای سفارشی (custom claims)"
description: "اطلاعاتی درباره‌ی کاربر را در همه‌ی توکن‌هایش بگذارید: طرح اشتراک، نقش، تیم‌هایی که عضو آن‌هاست. سرور شما آن‌ها را با کلید سرور می‌گذارد، قوانین امنیتی Sync آن‌ها را می‌خوانند و اپ با آن‌ها صفحه‌ی درست را نشان می‌دهد. همان مدل custom claims در Firebase."
product: auth
language: fa
url: https://abrova.ir/docs/auth/custom-claims
updated: 2026-11-05
---

# claimهای سفارشی (custom claims)

اطلاعاتی درباره‌ی کاربر را در همه‌ی توکن‌هایش بگذارید: طرح اشتراک، نقش، تیم‌هایی که عضو آن‌هاست. سرور شما آن‌ها را با کلید سرور می‌گذارد، قوانین امنیتی Sync آن‌ها را می‌خوانند و اپ با آن‌ها صفحه‌ی درست را نشان می‌دهد. همان مدل custom claims در Firebase.

> **یک واقعیت که همه‌ی محصولات به آن اعتماد می‌کنند**
>
> کاربری در سایت شما پرداخت کرده و حالا اپ باید درس‌های ویژه را برایش باز کند. فروشگاهی بعضی کاربران را کارمند می‌داند. اپ سازمانی می‌داند کاربر عضو کدام تیم‌هاست. **claimهای سفارشی** چنین اطلاعاتی را امضاشده داخل توکن کاربر می‌برند، پس همه‌ی محصولات ابرووا به آن‌ها اعتماد می‌کنند و اپ نمی‌تواند عوضشان کند. اگر custom claims در Firebase را می‌شناسید، این هم همان‌طور کار می‌کند.

## چطور کار می‌کند

1. **سرور شما claimها را برای کاربر می‌گذارد**، با کلید سرور پروژه: `setCustomUserClaims(userId, { plan: 'pro' })`.
2. **هر توکن تازه‌ی آن کاربر آن‌ها را دارد**، در سطح اول توکن کنار `sub` و `exp`. کاربر توکن تازه را در ورود یا تمدید بعدی می‌گیرد (حداکثر تا یک ساعت)، یا همان لحظه وقتی اپ توکن تازه بخواهد.
3. **قوانین امنیتی Sync آن‌ها را می‌خوانند**، به شکل `auth.token.plan`، و **اپ آن‌ها را می‌خواند** با `getTokenResult()` تا صفحه‌ی درست را نشان دهد.

این‌که کاربر چطور پرداخت کرده یا چرا کارمند است کار خود شماست: ابرووا فقط نتیجه را می‌برد.

## مرحله 1: گذاشتن claimها روی سرور

با [SDK مدیریتی](https://abrova.ir/docs/auth/admin-sdk) برای Node.js:

```ts
import { initAdmin } from '@abrova/auth-admin';

const auth = initAdmin(); // ABROVA_PROJECT_ID، ABROVA_API_KEY و ABROVA_SERVER_SECRET را می‌خواند

// بعد از این‌که سرور شما پرداخت را تأیید کرد:
await auth.setCustomUserClaims(userId, { plan: 'pro', levels: ['L1', 'L2'] });
```

یا با هر زبانی، با یک درخواست HTTPS:

```bash
curl -X PUT "https://auth-users.abrova.ir/v1/projects/$PROJECT_ID/users/$USER_ID/custom-claims" \
  -H "x-api-key: $ABROVA_API_KEY" \
  -H "x-server-secret: $ABROVA_SERVER_SECRET" \
  -H "content-type: application/json" \
  -d '{"claims": {"plan": "pro", "levels": ["L1", "L2"]}}'
```

`userId` شناسه‌ی کاربر ابرووا احراز هویت است (`ru_...`)، همان که اپ بعد از ورود می‌گیرد.

> **کلید سرور روی سرور شما می‌ماند**
>
> گذاشتن claim کلید سرور (`ab_srv_...`) می‌خواهد. هرگز آن را در اپ یا صفحه‌ی وب نگذارید، وگرنه هر کسی می‌تواند هر claimی به خودش بدهد. اپ فقط می‌تواند claimها را بخواند، نه بگذارد.

### گذاشتن claimها جایگزین می‌کند

هر فراخوانی **همه‌ی** claimهای کاربر را جایگزین می‌کند، مثل Firebase. برای اضافه کردن یک claim و نگه داشتن بقیه، اول آن‌ها را بخوانید:

```ts
const user = await auth.getUser(userId);
await auth.setCustomUserClaims(userId, { ...user.customClaims, beta: true });
```

برای پاک کردن همه‌ی claimها `null` (یا `{}`) بفرستید:

```ts
await auth.setCustomUserClaims(userId, null);
```

## مرحله 2: استفاده در قوانین امنیتی

قوانین Sync هر claim را به شکل `auth.token.<name>` می‌خوانند، مقدارهای تودرتو هم. claim متنی با نام `role` به شکل `auth.role` هم در دسترس است:

```json
{
  "rules": {
    "lessons": {
      "$id": {
        ".read": "auth.token.plan === 'pro' || data.free === true"
      }
    },
    "teams": {
      "$team": {
        ".write": "auth.token.teams.includes($team) && auth.token.team.role === 'editor'"
      }
    }
  }
}
```

کاربری که آن claim را ندارد از بررسی نمی‌گذرد. [قوانین امنیتی Sync](https://abrova.ir/docs/sync/rules) را ببینید.

## مرحله 3: خواندن در اپ

`getTokenResult()` توکن را با فیلدهای بازشده‌اش برمی‌گرداند، مثل `getIdTokenResult()` در Firebase. با آن صفحه‌ی درست را نشان دهید (نشان «Pro»، درس‌های بازشده). از نسخه‌ی **0.2.0** SDKهای ابرووا احراز هویت:

```ts
// Web، React Native
const result = await auth.getTokenResult();
if (result?.claims.plan === 'pro') showProBadge();
```

```dart
// Flutter
final result = await auth.getTokenResult();
if (result?.claims['plan'] == 'pro') showProBadge();
```

```swift
// iOS
let result = try await AbrovaAuth.shared.getTokenResult()
if result?.claims["plan"] as? String == "pro" { showProBadge() }
```

```kotlin
// Android
val result = AbrovaAuth.shared.getTokenResult()
if (result?.claims?.get("plan") == "pro") showProBadge()
```

| فیلد | چیست |
| --- | --- |
| `token` | خود access token، همان که getToken() می‌دهد. |
| `claims` | همه‌ی فیلدهای توکن: sub (شناسه‌ی کاربر)، pid، iat، exp، auth_time، amr و claimهای سفارشی شما. |
| `expirationTime` | زمان انقضای این توکن (در iOS: expirationDate، در Android: expirationTimestamp). |
| `issuedAtTime` | زمان صدور این توکن (در iOS: issuedAtDate، در Android: issuedAtTimestamp). |
| `authTime` | زمان ورود کاربر. تمدید آن را عوض نمی‌کند (در iOS: authDate، در Android: authTimestamp). |
| `signInProvider` | کاربر چطور وارد شده: anonymous، apple، google، password، magic_link یا telegram. |

> **برای نشان دادن، نه برای تصمیم گرفتن**
>
> اپ توکن خودش را می‌تواند بخواند، ولی تصمیم دسترسی فقط در اپ هیچ‌وقت امن نیست. صفحه‌ها را با `getTokenResult()` نشان دهید و داده را با قوانین امنیتی محافظت کنید که توکن امضاشده را روی سرور بررسی می‌کنند.

### گرفتن claimهای تازه همان لحظه

claim تغییرکرده با توکن بعدی به اپ می‌رسد، حداکثر تا یک ساعت. برای گرفتن آن همان لحظه، مثلاً با دکمه‌ی «بررسی خرید من» یا وقتی اپ باز می‌شود، توکن تازه بخواهید:

```ts
await auth.getTokenResult({ forceRefresh: true });
```

بعد به ابرووا سینک بگویید از آن استفاده کند: `sync.refreshUserToken()`.

## claim چه چیزی می‌تواند داشته باشد

| قاعده | حد |
| --- | --- |
| `مقدارها` | JSON: متن، عدد، true / false، null، فهرست و شیء. |
| `تودرتو` | فهرست‌ها و شیءها داخل هم، حداکثر ۵ سطح. |
| `اندازه` | همه‌ی claimهای یک کاربر روی هم حداکثر ۱۰۰۰ بایت، به صورت JSON. |
| `نام‌ها` | تا ۶۴ کاراکتر. نام‌هایی که خود توکن استفاده می‌کند رد می‌شوند، مثلاً sub، iss، aud، iat، exp، nbf، jti، auth_time و amr (پیام خطا نامی را که رد شد می‌گوید). |

درخواست ردشده با `400 INVALID_CLAIMS` و اولین مشکل جواب می‌گیرد و چیزی عوض نمی‌شود.

> **نه برای داده‌ی شخصی یا محرمانه**
>
> توکن امضا شده ولی رمزگذاری نشده است: هر کسی که دستگاه را دارد می‌تواند آن را بخواند. نقش، طرح اشتراک و شناسه را در claim بگذارید. هرگز ایمیل، شماره تلفن، قیمت یا کلید را نگذارید.

## خوب است بدانید

- **در همه‌ی طرح‌ها.** claimها هزینه‌ی اضافه ندارند: کاربری که claim دارد هنوز یک کاربر فعال ماهانه است.
- **نشست‌ها می‌مانند.** تغییر claimها هیچ‌وقت کاربر را خارج نمی‌کند. برای قطع دسترسی کاربر از [revokeRefreshTokens](https://abrova.ir/docs/auth/admin-sdk#revoke-refresh-tokens) استفاده کنید یا کاربر را در کنسول غیرفعال کنید.
- **کاربران ناشناس هم می‌توانند claim داشته باشند** و وقتی به حساب کامل [ارتقا](https://abrova.ir/docs/auth/upgrading) پیدا می‌کنند آن‌ها را نگه می‌دارند.
- **شنونده‌های باز Sync claimهای قبلی را نگه می‌دارند** تا وقتی تمدید شوند، حداکثر ۲۴ ساعت. برای محتوای پولی که کاربر ممکن است از دست بدهد، claim را در یک خواندن معمولی هم بررسی کنید، یا وقتی سرور شما claim را برمی‌دارد شنونده را در اپ ببندید.
- **در کنسول**، بخش ابرووا احراز هویت › کاربران کاربرانی را که claim دارند علامت می‌زند و claimها را فقط‌خواندنی نشان می‌دهد. هر تغییر در فعالیت‌ها با عنوان «ادعاهای سفارشی تغییر کرد» و بدون مقدارها دیده می‌شود.
- **توکن‌هایی که سرور خودتان می‌سازد** (`POST /users/token` با `claims`) همین قاعده‌ها را دارند و claimها را در همان جای توکن می‌گذارند، پس قوانین آن‌ها را به همان شکل می‌خوانند.
