راهنماها
احراز هویت
مهوش دو نوع bearer token دارد. در این صفحه میبینید هر کدام نشاندهندهٔ چیست، کدام endpointها آن را میپذیرند، API key پروژه چطور صادر و جایگزین میشود و چطور secretها را از دسترس دیگران دور نگه دارید.
دو نوع credential
هر request احرازشده یک header به شکل Authorization: Bearer <token> دارد. این token یکی از دو چیز کاملاً متفاوت است:
| credential | نشاندهندهٔ | مناسب برای | دامنه و طول عمر |
|---|---|---|---|
API key پروژه (mk_...) | دسترسی دائمی یک سیستم، با همان مجوزهای کسی که کلید را صادر کرده | requestهای هوش مصنوعی از سرور به سرور | فقط یک سازمان و یک پروژه؛ scope و تاریخ انقضای اختیاری؛ فقط یک بار نمایش داده میشود |
| JWT کاربر | یک کاربرِ واردشده | راهاندازی و مدیریت فضای کاری و صدور کلید | عضویتها و نقشهای فعال همان شخص؛ کوتاهعمر و قابل تمدید با refresh token |
قاعدهٔ کلی ساده است: نرمافزار از API key پروژه استفاده میکند و آدمها از JWT. سرویسی که پیشنویس پاسخ پشتیبانی مینویسد باید API key پروژه داشته باشد. اما مدیری که پروژه و کلید آن سرویس را میسازد، این کار را با JWT خودش انجام میدهد تا نامش در سابقهٔ تغییرات ثبت شود.
در مرجع API برای هر endpoint نوشتهایم کدام credential را میپذیرد. endpointهای هوش مصنوعی زیر /v1 هر دو را قبول میکنند؛ اما مدیریت فضای کاری زیر /api/v1/tenancy و مدیریت webhookها فقط با JWT کاربر ممکن است.
token کاربر
کاربران با شمارهٔ موبایل و یک کد یکبارمصرف وارد میشوند. اگر کد درست باشد، یک access token و یک refresh token برمیگردد:
# 1. Ask for a one-time code (sent by SMS to the phone number)
curl -X POST https://api.mahvashai.ir/api/v1/users/register/ \
-H "Content-Type: application/json" \
-d '{"phone": "09XXXXXXXXX"}'
# 2. Verify the code and receive a token pair
curl -X POST https://api.mahvashai.ir/api/v1/users/register/auth/ \
-H "Content-Type: application/json" \
-d '{"phone": "09XXXXXXXXX", "otp": "<code>"}'اولین ورود موفق با هر شماره، حساب کاربری را میسازد (created: true) و همزمان یک سازمان شخصی و یک پروژهٔ پیشفرض هم برایش ایجاد میکند؛ پس کاربر تازه بلافاصله میتواند request بفرستد.
access token تاریخ انقضا دارد. وقتی پاسخ 401 گرفتید، refresh token را بفرستید تا یک جفت token تازه بگیرید:
curl -X POST https://api.mahvashai.ir/api/v1/users/refresh/ \
-H "Content-Type: application/json" \
-d '{"refresh": "<user-refresh-jwt>"}'- هر refresh token فقط یک بار قابل استفاده است. جفت تازه را ذخیره کنید و قبلی را کنار بگذارید.
- فقط پاسخ
401از endpoint تمدید به این معناست که نشست تمام شده است.409 refresh_token_rotatedیعنی request دیگری همین token را چند لحظه پیش تمدید کرده؛429و503هم موقتیاند. در این موارد tokenها را نگه دارید و کمی بعد دوباره امتحان کنید. - تمدید token را فقط از یک جا انجام دهید. دو تمدید همزمان با یک token نمیتوانند هر دو موفق شوند.
نکته:بیشتر یکپارچهسازیها فقط هنگام راهاندازی به JWT نیاز دارند؛ برای ساخت پروژه و صدور کلید. requestهای هوش مصنوعی در production باید با API key پروژه فرستاده شوند، نه با token یک شخص.
صدور API key پروژه
کلید برای یک پروژهٔ مشخص و توسط کسی صادر میشود که مدیر همان پروژه باشد. این کار را هم از داشبورد و هم از طریق API میتوانید انجام دهید:
curl -X POST https://api.mahvashai.ir/api/v1/tenancy/projects/<project-uuid>/credentials \
-H "Authorization: Bearer $MAHVASH_USER_JWT" \
-H "X-Mahvash-Organization: acme" \
-H "Content-Type: application/json" \
-d '{
"name": "production-backend",
"scopes": ["models.request", "chat.read"],
"expires_at": "2027-06-30T00:00:00Z"
}'name(الزامی) یک برچسب برای شناسایی کلید است. کلید را به اسم سیستم و محیطی نامگذاری کنید که از آن استفاده میکند.scopesکارهایی را که کلید مجاز به انجامشان است محدود میکند. اگر آن را نفرستید یا[]بفرستید، کلید همهٔ کارهای مجاز در پروژه را میتواند انجام دهد.expires_atکلید را در زمان مشخصی از کار میاندازد؛ برای پیمانکاران یا آزمایشهای موقت مفید است.attributed_teamمصرف کلید را در گزارشها به یک تیم نسبت میدهد. این فقط یک برچسب است و دسترسی تازهای نمیدهد.
مقدار token فقط یک بار در پاسخ میآید. آن را مستقیم در سامانهٔ مدیریت secretها ذخیره کنید. prefix (مثلاً mk_1a2b3c4d5e6f) بخش عمومی کلید است؛ ثبت آن در لاگ امن است و برای شناسایی یا باطل کردن کلید کافی است.
بعد کلید را بهعنوان bearer token بفرستید:
curl https://api.mahvashai.ir/v1/responses \
-H "Authorization: Bearer $MAHVASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "auto", "input": "Ping"}'Scopeها: کمترین دسترسی لازم
با scopeها هر کلید را به همان کارهایی محدود میکنید که یک سیستم مشخص لازم دارد. کلیدی که فقط پیشنویس پاسخ میسازد، نیازی به حذف فایل ندارد.
| scope | چه اجازهای میدهد |
|---|---|
models.request | ساختن response، chat completion، تصویر، صوت، embedding و moderation |
chat.read / chat.write | خواندن گفتوگوها و runها / لغو و حذف آنها |
files.read / files.write | خواندن assetها و آپلودها / ساختن و حذف آنها |
vector_stores.read / vector_stores.write | خواندن vector storeها و فایلهایشان / ساختن، ویرایش، حذف و جابهجایی آنها |
prompts.read / prompts.write | خواندن promptهای پروژه / ویرایش آنها |
projects.read | خواندن اطلاعات پروژه و سازمان انتخابشده |
usage.read | دیدن مصرف همین حساب |
- هر scope از نوع
*.write، scope متناظر*.readرا هم در بر میگیرد؛ پس کلیدی که vector store میسازد، میتواند آن را بخواند. models.requestشامل خواندن تاریخچه نمیشود. کلیدی که هم prompt میفرستد و گفتوگوهای ذخیرهشده را میخواند، بهmodels.requestوchat.readنیاز دارد.- scope ناشناخته همان لحظهٔ صدور کلید رد میشود و هیچوقت بیصدا نادیده گرفته نمیشود؛ پس یک اشتباه تایپی هرگز کلیدی با دسترسی بیشتر از خواستهٔ شما نمیسازد.
کارهایی که کلید هرگز نمیتواند انجام دهد
API key پروژه، با هر scopeی و هر سازندهای، نمیتواند سازمان را مدیریت کند. این کارها برای همهٔ کلیدها ممنوع است:
- دعوت یا حذف اعضا و تغییر نقش آنها؛
- مدیریت تیمها و دسترسیهای پروژه (grantها)؛
- صدور، جایگزینی یا باطل کردن API key؛
- مدیریت webhookها؛
- دیدن سابقهٔ تغییرات (audit) یا گزارش مصرف کل سازمان، و هر کاری که به کیف پول مربوط باشد.
کلید همیشه با دسترسی فعلیِ کسی که آن را صادر کرده و فقط در پروژهٔ خودش کار میکند؛ هرگز بیشتر از آن. اگر نقش آن شخص پایین بیاید، دسترسی کلید هم کم میشود. اگر آن شخص از سازمان حذف یا تعلیق شود، همهٔ کلیدهایی که صادر کرده همان لحظه باطل میشوند و حتی اگر دوباره عضو شود، باطل میمانند. برای این اتفاق برنامه داشته باشید: وقتی عضوی که مسئول یک یکپارچهسازی است از تیم میرود، پیش از حذف او، کلید جایگزین را با حساب یک مدیر دیگر صادر کنید.
هر کلید به سازمان و پروژهٔ خودش گره خورده است. اگر request مقدار متفاوتی در X-Mahvash-Organization یا X-Mahvash-Project بفرستد، رد میشود؛ نه اینکه بیصدا به جای دیگری برود.
جایگزینی و باطل کردن کلید
با کلیدها مثل رمز عبوری رفتار کنید که چرخهٔ عمر دارد:
# Planned replacement: the old key keeps working during the overlap window
curl -X POST https://api.mahvashai.ir/api/v1/tenancy/credentials/<credential-uuid>/rotate \
-H "Authorization: Bearer $MAHVASH_USER_JWT" \
-H "X-Mahvash-Organization: acme"
# Suspected leak: stop the key immediately
curl -X DELETE https://api.mahvashai.ir/api/v1/tenancy/credentials/<credential-uuid> \
-H "Authorization: Bearer $MAHVASH_USER_JWT" \
-H "X-Mahvash-Organization: acme"- Rotate برای جایگزینی برنامهریزیشده است. کلید تازه میگیرید و کلید قبلی تا پایان یک بازهٔ همپوشانی (بهطور پیشفرض ۲۴ ساعت) کار میکند تا بتوانید کلید تازه را بدون قطعی سرویس جایگزین کنید.
- Revoke برای وقتی است که احتمال میدهید کلید لو رفته باشد. کلید همان لحظه از کار میافتد.
کلیدهای باطلشده در فهرست باقی میمانند تا هنگام بررسی یک رخداد معلوم باشد هر کلید کی وجود داشته و کی متوقف شده است. برای اینکه بدانید کلیدی همین حالا کار میکند یا نه، فیلد usable را ببینید؛ چون ممکن است وضعیت کلیدی ACTIVE باشد ولی تاریخ انقضایش گذشته باشد.
نگهداری امن
- کلیدها و tokenها را فقط روی سرورهای مطمئن، در متغیرهای محیطی یا سامانهٔ مدیریت secretها نگه دارید.
- کلید یا token را هیچوقت در کد مرورگر، بستهٔ اپ موبایل، URL یا query string، لاگ، رویدادهای تحلیلی، اسکرینشات یا مخزن عمومی قرار ندهید.
- برای هر سیستم و هر محیط کلید جداگانه بسازید تا بتوانید یکی را بدون اختلال در بقیه باطل کنید.
- به هر کلید کمترین scope لازم را بدهید و اگر استفاده موقتی است، برایش تاریخ انقضا بگذارید.
- برای ردگیری یک فراخوانی،
X-Request-IDو پیشوند کلید را در لاگ بنویسید؛ هرگز خود کلید را.
مهم:اگر کلیدی لو رفت، اول آن را revoke کنید و بعد سراغ بررسی بروید. کلیدی که rotate شده در بازهٔ همپوشانی هنوز کار میکند؛ پس rotate پاسخ درستی به لو رفتن کلید نیست.