آشنایی با OAuth 2 (معرفی جامع)

مقدمه
پروتکل OAuth 2 به اپلیکیشنهای شخص ثالث اجازه میدهد تا بدون نیاز به مدیریت رمزهای عبور کاربران، به دادههای آنها دسترسی پیدا کنند. به جای درخواست اعتبارنامه (نام کاربری و رمز عبور) از کاربر، OAuth 2 فرآیند احراز هویت را به ارائهدهنده سرویس (مانند گوگل یا گیتهاب) واگذار میکند و توکنهایی (Tokens) صادر میکند که نمایانگر دسترسیهای خاصی هستند.
نکته مهمی که باید بدانید این است: OAuth 2 یک چارچوب مجوزدهی (Authorization) است، نه احراز هویت (Authentication). این پروتکل به این سوال پاسخ میدهد که «این اپلیکیشن چه کاری میتواند انجام دهد؟» نه اینکه «این کاربر کیست؟». زمانی که در یک وبسایت روی دکمه «ورود با گوگل» (Sign in with Google) کلیک میکنید، معمولاً از پروتکل OpenID Connect (که لایه احراز هویت را اضافه میکند) در بالای OAuth 2 استفاده میشود.
چرا OAuth 2 به وجود آمد؟ پیش از OAuth 2، اپلیکیشنها یا از کاربران رمز عبور میخواستند (که یک ریسک امنیتی بزرگ است) و یا از آنها میخواستند کلیدهای API خود را به اشتراک بگذارند (که دسترسیهای بیش از حد و خطرناکی میداد). OAuth 2 این مشکل را با اجازه دادن به کاربران برای اعطای دسترسیهای محدود و قابل لغو حل میکند. به عنوان مثال، یک اپلیکیشن بکآپ میتواند بدون نیاز به رمز عبور گوگل شما، به فایلهای گوگل درایو شما دسترسی پیدا کند و شما میتوانید این دسترسی را در هر زمان لغو کنید.
این راهنما به شما نشان میدهد که OAuth 2 چگونه کار میکند، برای سناریوهای مختلف از کدام نوع اعطای دسترسی (Grant Type) استفاده کنید و چگونه میتوانید جریانهای امن OAuth 2 را در اپلیکیشنهای خود پیادهسازی کنید.
نکات کلیدی
پیش از ورود به جزئیات فنی، این نکات ضروری درباره OAuth 2 را در نظر داشته باشید:
- OAuth 2 مجوزدهی را ارائه میکند، نه احراز هویت. این پروتکل به اپلیکیشنها اجازه میدهد برای دسترسی به منابع مجوز دریافت کنند، اما به تنهایی هویت کاربر را تایید نمیکند.
- جریان OAuth 2 توسط چهار نقش اصلی تعریف میشود: مالک منبع (Resource Owner)، کلاینت (Client)، سرور مجوزدهی (Authorization Server) و سرور منبع (Resource Server).
- اعطای کد مجوزدهی (Authorization Code) رویکرد استاندارد برای اپلیکیشنهای سمت سرور است که در آنها راز کلاینت (Client Secret) میتواند محرمانه بماند.
- PKCE (Proof Key for Code Exchange) برای کلاینتهای عمومی (مانند اپلیکیشنهای موبایل و SPAها) ضروری است، زیرا از حملات ربوده شدن کد مجوزدهی جلوگیری میکند.
- توکنهای صادر شده توسط OAuth 2 عمر محدودی دارند؛ توکنهای دسترسی (Access Tokens) منقضی میشوند و توکنهای بازنشانی (Refresh Tokens) به اپلیکیشنها اجازه میدهند بدون دخالت کاربر، توکن دسترسی جدیدی دریافت کنند.
- اسکوپها (Scopes) در OAuth 2 دسترسیهای درخواست شده را تعریف میکنند.
- OAuth 1 اکنون منسوخ شده است. OAuth 2 به دلیل امنیت بهبود یافته و فرآیند پیادهسازی سادهتر، جایگزین OAuth 1.0 شده است.
OAuth 2 چیست؟
OAuth 2 یک چارچوب مجوزدهی است (در RFC 6749 تعریف شده است) که به اپلیکیشنهای شخص ثالث اجازه میدهد دسترسی محدودی به منابع کاربر روی یک سرویس HTTP به دست آورند.
به OAuth 2 مانند یک کلید پارکبان (Valet Key) برای ماشین خود فکر کنید: شما یک کلید با استفاده محدود به پارکبان میدهید که فقط درها را باز کرده و ماشین را روشن میکند، اما صندوق عقب یا داشبورد را باز نمیکند. به طور مشابه، OAuth 2 به اپلیکیشنها دسترسیهای خاصی (اسکوپها) برای دسترسی به منابع مشخصی میدهد، بدون اینکه دسترسی کامل به حساب کاربری بدهد.
OAuth 2 یک مشکل امنیتی بحرانی را حل میکند: اپلیکیشنها دیگر نیازی به ذخیره رمزهای عبور کاربران ندارند. در عوض، کاربران از طریق ارائهدهنده سرویس (مانند گوگل یا گیتهاب) به اپلیکیشنها مجوز میدهند.
نحوه کار OAuth 2: جریان پایه
OAuth 2 بدون توجه به نوع اعطای دسترسی، از یک الگوی ۶ مرحلهای پیروی میکند:
- درخواست مجوزدهی: اپلیکیشن شما کاربر را به سرور مجوزدهی هدایت میکند تا دسترسیهای خاصی (اسکوپها) را درخواست کند.
- تایید کاربر: کاربر وارد سیستم میشود (در صورت نیاز) و درخواست اپلیکیشن شما را تایید یا رد میکند. در صورت تایید، سرور یک کد مجوزدهی (Authorization Grant) تولید میکند.
- درخواست توکن دسترسی: اپلیکیشن شما کد مجوزدهی را (به همراه اعتبارنامههای کلاینت خود) با یک توکن دسترسی (Access Token) تعویض میکند. این کار سرور به سرور انجام میشود.
- صدور توکن دسترسی: سرور در صورت صحت اطلاعات، یک توکن دسترسی (و اختیاریاً یک توکن بازنشانی) به اپلیکیشن شما برمیگرداند.
- درخواست منبع محافظت شده: اپلیکیشن شما از توکن دسترسی برای ارسال درخواستهای API به نمایندگی از کاربر استفاده میکند.
- سرو کردن منبع: API توکن را اعتبارسنجی کرده و در صورت معتبر بودن، دادههای درخواست شده را برمیگرداند.
تفاوت OAuth 2، احراز هویت و OpenID Connect
- OAuth 2 (مجوزدهی): به سوال «این اپلیکیشن چه کاری میتواند انجام دهد؟» پاسخ میدهد. هویت کاربر را تایید نمیکند.
- احراز هویت (Authentication): هویت کاربر را تایید میکند. به سوال «این کاربر کیست؟» پاسخ میدهد.
- OpenID Connect (OIDC): احراز هویت را به OAuth 2 اضافه میکند و یک «توکن ID» حاوی اطلاعات هویتی کاربر صادر میکند. وقتی دکمه «ورود با گوگل» را میبینید، معمولاً از OIDC استفاده میشود.
نقشهای OAuth 2
- مالک منبع (Resource Owner): کاربری که مالک دادهها است و میتواند دسترسی به آنها را اعطا کند.
- کلاینت (Client): اپلیکیشنی (موبایل، وب یا سمت سرور) که درخواست دسترسی به منابع کاربر را دارد.
- سرور مجوزدهی (Authorization Server): سروری که کاربر را احراز هویت کرده و پس از موفقیتآمیز بودن مجوزدهی، توکنهای دسترسی را صادر میکند.
- سرور منبع (Resource Server): سروری که منابع محافظت شده (دادهها، APIها) را میزبانی میکند. این سرور توکنهای دسترسی را اعتبارسنجی میکند. (در API پارمین کلود، این سرور و سرور مجوزدهی معمولاً با هم ترکیب شدهاند).
ثبت اپلیکیشن و اعتبارنامههای کلاینت
پیش از استفاده از OAuth 2، باید اپلیکیشن خود را در پورتال توسعهدهندگان سرویس ثبت کنید. در طول ثبتنام باید موارد زیر را وارد کنید:
- نام اپلیکیشن: نامی که کاربران در صفحه تایید دسترسی میبینند.
- آدرس وبسایت اپلیکیشن: صفحه اصلی اپلیکیشن شما.
- آدرس Redirect (Callback URL): آدرس دقیقی که سرور مجوزدهی کاربر را پس از تایید یا رد درخواست به آن ارسال میکند. این آدرس باید دقیقاً با آنچه در درخواستها میفرستید مطابقت داشته باشد.
پس از ثبت، سرویس به شما اعتبارنامههای کلاینت را میدهد:
- Client ID: رشتهای عمومی برای شناسایی اپلیکیشن شما. ایمن است که در کدهای سمت کلاینت یا URLها استفاده شود.
- Client Secret: رشتهای محرمانه که اپلیکیشن شما را در برابر سرور مجوزدهی احراز هویت میکند. هرگز این رشته را در کدهای فرانتاند، اپلیکیشنهای موبایل، گیتهاب یا URLها فاش نکنید.
انواع اعطای دسترسی (Grant Types) در OAuth 2
یک اعطای دسترسی، یک اعتبارنامه است که نشاندهنده مجوز مالک منبع برای دسترسی به منابع محافظت شده است. OAuth 2 چندین نوع اعطای دسترسی را تعریف میکند:
- Authorization Code (کد مجوزدهی): رایجترین نوع، مخصوص اپلیکیشنهای سمت سرور. توکن دسترسی هرگز در معرض مرورگر قرار نمیگیرد؛ فقط کد مجوزدهی منتقل میشود که سپس در سمت سرور با توکن تعویض میشود.
- Client Credentials (اعتبارنامههای کلاینت): برای ارتباط ماشین به ماشین (بدون حضور کاربر). اپلیکیشن با اعتبارنامههای خودش احراز هویت میشود.
- Device Code (کد دستگاه): برای دستگاههای دارای محدودیت ورودی (تلویزیونهای هوشمند، اینترنت اشیا) که مرورگر یا کیبورد ندارند.
(نکته: جریان Implicit و Password در نسخههای جدیدتر منسوخ و غیرامن شدهاند و نباید استفاده شوند).
جریان کد مجوزدهی (Authorization Code Flow) – گام به گام
مرحله ۱: ساخت URL مجوزدهی
اپلیکیشن کاربر را به URL سرور مجوزدهی هدایت میکند. (نمونه با فرض استفاده از API پارمین کلود):
https://cloud.parmincloud.com/v1/oauth/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=CALLBACK_URL&scope=read&state=RANDOM_STATE_STRING
response_type=code: درخواست کد مجوزدهی.state: یک مقدار تصادفی برای جلوگیری از حملات CSRF. این مقدار را در سشن کاربر ذخیره کرده و هنگام دریافت کالبک آن را اعتبارسنجی کنید.
مرحله ۲: تایید کاربر
کاربر وارد سیستم میشود و صفحه Consent (رضایت) را میبیند که نشان میدهد کدام اپلیکیشن و چه دسترسیهایی را میخواهد. کاربر تایید میکند.
مرحله ۳: دریافت کد مجوزدهی
سرور کاربر را به آدرس Redirect شما برمیگرداند:
https://your-app.com/callback?code=AUTHORIZATION_CODE&state=RANDOM_STATE_STRING
این کد کوتاهعمر (معمولاً کمتر از ۱۰ دقیقه) و یکبارمصرف است.
مرحله ۴: تعویض کد با توکن دسترسی
سرور شما یک درخواست POST به مسیر توکن ارسال میکند:
POST https://cloud.parmincloud.com/v1/oauth/token
Content-Type: application/x-www-form-urlencoded
client_id=CLIENT_ID&client_secret=CLIENT_SECRET&grant_type=authorization_code&code=AUTHORIZATION_CODE&redirect_uri=CALLBACK_URL
مرحله ۵: دریافت توکن دسترسی
اگر کد معتبر باشد، سرور پاسخ میدهد:
{
"access_token": "ACCESS_TOKEN",
"token_type": "bearer",
"expires_in": 2592000,
"refresh_token": "REFRESH_TOKEN",
"scope": "read"
}
مثال کامل پیادهسازی (Node.js / Express)
این کد یک سرور Express آماده برای تولید را نشان میدهد که شامل اعتبارسنجی پارامتر state، مدیریت خطا، و بازنشانی خودکار توکن است:
// مثال Express.js - جریان کد مجوزدهی OAuth 2
const express = require('express');
const crypto = require('crypto');
const axios = require('axios');
const app = express();
const CLIENT_ID = process.env.OAUTH_CLIENT_ID;
const CLIENT_SECRET = process.env.OAUTH_CLIENT_SECRET;
const REDIRECT_URI = 'https://your-app.com/callback';
const AUTHORIZATION_URL = 'https://cloud.parmincloud.com/v1/oauth/authorize';
const TOKEN_URL = 'https://cloud.parmincloud.com/v1/oauth/token';
// ذخیره مقدار state در سشن (در محیط تولید از Redis استفاده کنید)
const stateStore = new Map();
// مرحله ۱: هدایت کاربر به سرور مجوزدهی
app.get('/auth', (req, res) => {
// تولید یک مقدار state تصادفی و امن
const state = crypto.randomBytes(32).toString('hex');
stateStore.set(state, { timestamp: Date.now() });
const authUrl = new URL(AUTHORIZATION_URL);
authUrl.searchParams.set('response_type', 'code');
authUrl.searchParams.set('client_id', CLIENT_ID);
authUrl.searchParams.set('redirect_uri', REDIRECT_URI);
authUrl.searchParams.set('scope', 'read write');
authUrl.searchParams.set('state', state);
res.redirect(authUrl.toString());
});
// مرحله ۲-۴: مدیریت کالبک و تعویض کد با توکن
app.get('/callback', async (req, res) => {
const { code, state, error } = req.query;
// اعتبارسنجی پارامتر state
if (!stateStore.has(state)) {
return res.status(400).send('پارامتر state نامعتبر است');
}
stateStore.delete(state); // فقط یک بار استفاده شود
if (error) {
return res.status(400).send(`مجوزدهی ناموفق بود: ${error}`);
}
try {
// تعویض کد مجوزدهی با توکن دسترسی
const tokenResponse = await axios.post(TOKEN_URL,
new URLSearchParams({
grant_type: 'authorization_code',
code: code,
redirect_uri: REDIRECT_URI,
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET
}), {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
}
);
const { access_token, refresh_token, expires_in } = tokenResponse.data;
req.session.accessToken = access_token;
req.session.refreshToken = refresh_token;
req.session.tokenExpiry = Date.now() + (expires_in * 1000);
res.redirect('/dashboard');
} catch (error) {
res.status(500).send('تعویض توکن ناموفق بود');
}
});
اثبات کلید برای تبادل کد (PKCE)
PKCE (تلفظ میشود “پیکسی”) یک افزونه امنیتی برای جریان کد مجوزدهی است که از ربوده شدن کد جلوگیری میکند. این مورد برای کلاینتهای عمومی (موبایل، SPA) که نمیتوانند Client Secret را امن نگه دارند، ضروری است.
چرا PKCE مهم است؟
بدون PKCE، یک اپلیکیشن مخرب میتواند با ثبت یک URL Scheme دلخواه روی موبایل شما، کد مجوزدهی اپلیکیشن قانونی را ربوده و آن را با Client ID عمومی اپلیکیشن قانونی با توکن تعویض کند.
با PKCE، اپلیکیشن قانونی پیش از شروع جریان یک رشته تصادفی مخفی (code_verifier) تولید کرده و هش آن (code_challenge) را به سرور میفرستد. هنگام تعویض کد با توکن، اپلیکیشن باید code_verifier اصلی را ارسال کند. اپلیکیشن مخرب چون به این رشته دسترسی ندارد، نمیتواند توکن را دریافت کند.
استفاده از توکنهای دسترسی
پس از دریافت توکن، آن را در هدر HTTP با فرمت Bearer قرار دهید:
curl -X GET \
-H "Authorization: Bearer ACCESS_TOKEN" \
https://api.parmincloud.com/v2/droplets
اگر توکن نامعتبر باشد، خطای 401 Unauthorized دریافت میکنید و باید آن را با Refresh Token بازنشانی کنید.
جریان توکن بازنشانی (Refresh Token)
توکنهای دسترسی عمر کوتاهی دارند (۱ ساعت تا ۳۰ روز). برای اینکه کاربر مجبور نشود دوباره لاگین کند، از توکن بازنشانی استفاده کنید:
POST https://cloud.parmincloud.com/v1/oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token&client_id=CLIENT_ID&client_secret=CLIENT_SECRET&refresh_token=REFRESH_TOKEN
سرور در پاسخ یک توکن دسترسی جدید (و گاهی یک توکن بازنشانی جدید) به شما میدهد.
چه زمانی از OAuth 2 استفاده نکنیم؟
- سیستم لاگین داخلی اپلیکیشن خودتان: اگر کاربران مستقیماً به اپلیکیشن شما لاگین میشوند، نیازی به OAuth 2 ندارید. از احراز هویت مبتنی بر سشن (Session) استفاده کنید.
- ارتباط بین میکروسرویسهای داخلی: از mTLS یا API Gateway استفاده کنید.
- دسترسی به دادههای عمومی API: اگر دادهها نیاز به مجوز کاربر ندارند، از کلیدهای API ساده استفاده کنید.
اشتباهات رایج در پیادهسازی OAuth 2
- عدم اعتبارسنجی دقیق Redirect URI: آدرسها باید کاراکتر به کاراکتر (حساس به اسلش / و پورت) مطابقت داشته باشند. از Wildcard (*) استفاده نکنید.
- نادیده گرفتن پارامتر State: این کار اپلیکیشن شما را در برابر حملات CSRF آسیبپذیر میکند.
- ذخیره ناامن توکنها: توکنها را در
localStorageذخیره نکنید (آسیبپذیر در برابر XSS). از کوکیهایHttpOnlyسمت سرور یا Keychain در موبایل استفاده کنید. - درخواست اسکوپهای بیش از حد (Scope Creep): فقط حداقل دسترسیهای لازم را درخواست کنید تا کاربران با اعتماد بیشتری مجوز بدهند.
رفع مشکلات رایج OAuth 2
- خطای
invalid_client: Client ID یا Secret اشتباه کپی شده یا تغییر کرده است. - خطای
invalid_grant: کد مجوزدهی منقضی شده (بیشتر از ۱۰ دقیقه گذشته)، قبلاً استفاده شده، یا آدرس Redirect URI در مرحله تعویض توکن دقیقاً مطابقت ندارد. - خطای
redirect_uri_mismatch: آدرس ارسالی شما با آدرس ثبت شده در پورتال توسعهدهندگان تطابق ندارد (توجه بهhttpvshttpsو اسلش انتهایی). - خطای
access_denied: کاربر دسترسی اپلیکیشن شما را در صفحه تایید رد کرده است.
نتیجهگیری
OAuth 2 استاندارد صنعتی برای مجوزدهی امن و واگذار شده است. این پروتکل به اپلیکیشنها اجازه میدهد بدون مدیریت رمزهای عبور به منابع کاربر دسترسی پیدا کنند. همیشه از جریان Authorization Code همراه با PKCE استفاده کنید، آدرسهای Redirect را به دقت اعتبارسنجی کنید، توکنها را به صورت امن ذخیره کرده و تنها حداقل اسکوپهای مورد نیاز را درخواست کنید.




