hesabixCore/docs/OAuth/OAuth_Complete_Documentation.md
2025-08-16 12:13:39 +00:00

27 KiB
Raw Permalink Blame History

مستندات کامل سیستم OAuth 2.0 - Hesabix

📋 فهرست مطالب

  1. معرفی OAuth 2.0
  2. معماری سیستم
  3. بخش مدیریت
  4. بخش کاربری
  5. API Documentation
  6. نحوه اتصال
  7. امنیت
  8. مثال‌های عملی
  9. عیب‌یابی
  10. پشتیبانی

🚀 معرفی OAuth 2.0

OAuth 2.0 یک پروتکل استاندارد برای احراز هویت و مجوزدهی است که به برنامه‌های خارجی اجازه می‌دهد بدون نیاز به رمز عبور، به حساب کاربران دسترسی داشته باشند.

مزایای OAuth 2.0:

  • امنیت بالا: عدم اشتراک‌گذاری رمز عبور
  • کنترل دسترسی: محدود کردن دسترسی‌ها با Scope
  • قابلیت لغو: امکان لغو دسترسی در هر زمان
  • استاندارد: سازگار با پروتکل‌های جهانی
  • IP Whitelist: کنترل دسترسی بر اساس IP
  • Rate Limiting: محدودیت تعداد درخواست

🏗️ معماری سیستم

اجزای اصلی:

┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   Client App    │    │  OAuth Server   │    │  Resource Owner │
│  (Third Party)  │◄──►│   (Hesabix)     │◄──►│     (User)      │
└─────────────────┘    └─────────────────┘    └─────────────────┘

جریان OAuth:

  1. Client Registration: ثبت برنامه در بخش مدیریت
  2. Authorization Request: درخواست مجوز از کاربر
  3. User Consent: تأیید کاربر
  4. Authorization Code: دریافت کد مجوز
  5. Token Exchange: تبدیل کد به Access Token
  6. Resource Access: دسترسی به منابع

پایگاه داده:

-- جداول OAuth
oauth_application     -- برنامه‌های ثبت شده
oauth_scope          -- محدوده‌های دسترسی
oauth_authorization_code  -- کدهای مجوز موقت
oauth_access_token   -- توکن‌های دسترسی

⚙️ بخش مدیریت

1. دسترسی به بخش مدیریت

مدیریت سیستم → تنظیمات سیستم → تب "برنامه‌های OAuth"

2. آمار کلی

سیستم چهار کارت آمار نمایش می‌دهد:

  • کل برنامه‌ها: تعداد کل برنامه‌های ثبت شده
  • فعال: تعداد برنامه‌های فعال
  • غیرفعال: تعداد برنامه‌های غیرفعال
  • جدید (7 روز): برنامه‌های ایجاد شده در هفته گذشته

3. ایجاد برنامه جدید

مراحل ایجاد:

  1. کلیک روی "ایجاد برنامه جدید"
  2. پر کردن فرم:
    • نام برنامه: نام منحصر به فرد برنامه
    • توضیحات: توضیح کاربرد برنامه
    • آدرس وب‌سایت: URL اصلی برنامه
    • آدرس بازگشت: URL callback برنامه
    • محدودیت درخواست: تعداد درخواست مجاز در ساعت

تنظیمات امنیتی:

IP Whitelist:
- در صورت خالی بودن: از هر IP مجاز است
- افزودن IP: 192.168.1.1 یا 192.168.1.0/24
- پشتیبانی از CIDR notation
- Validation خودکار آدرس‌های IP
Scope Management:
read_profile     - دسترسی به اطلاعات پروفایل
write_profile    - تغییر اطلاعات پروفایل
read_business    - دسترسی به اطلاعات کسب و کار
write_business   - تغییر اطلاعات کسب و کار
read_financial   - دسترسی به اطلاعات مالی
write_financial  - تغییر اطلاعات مالی
read_contacts    - دسترسی به لیست مخاطبین
write_contacts   - تغییر لیست مخاطبین
read_documents   - دسترسی به اسناد
write_documents  - تغییر اسناد
admin_access     - دسترسی مدیریتی

4. مدیریت برنامه‌ها

کارت برنامه:

  • وضعیت: فعال/غیرفعال با رنگ‌بندی
  • Client ID: شناسه یکتا برنامه
  • تاریخ ایجاد: تاریخ ثبت برنامه
  • توضیحات: شرح برنامه

عملیات موجود:

دکمه‌های اصلی:
  • ویرایش: تغییر اطلاعات برنامه
  • آمار: مشاهده آمار استفاده
  • فعال/غیرفعال: تغییر وضعیت برنامه
منوی سه نقطه:
  • بازسازی کلید: تولید Client Secret جدید
  • لغو توکن‌ها: لغو تمام توکن‌های فعال
  • حذف: حذف کامل برنامه

5. اطلاعات امنیتی

پس از ایجاد برنامه، اطلاعات زیر نمایش داده می‌شود:

Client ID:     mL0qT1fkIL6MCJfxIPAh7nM2cQ7ykxEy
Client Secret: goM7latD9akY83z2O2e9IIEYED3Re6sRMd36f5cUSYHm389PPSqYbFHSX8GtQ9H1

⚠️ هشدار: این اطلاعات را در جای امنی ذخیره کنید!


👤 بخش کاربری

1. صفحه مجوزدهی

هنگام اتصال برنامه خارجی، کاربر به صفحه زیر هدایت می‌شود:

┌─────────────────────────────────────┐
│           مجوزدهی OAuth             │
├─────────────────────────────────────┤
│                                     │
│  [آیکون برنامه] نام برنامه         │
│  توضیحات برنامه...                 │
│                                     │
│  این برنامه درخواست دسترسی به:      │
│  ✓ خواندن اطلاعات پروفایل          │
│  ✓ خواندن اطلاعات کسب و کار         │
│                                     │
│  [لغو] [تأیید]                     │
└─────────────────────────────────────┘

2. اطلاعات نمایش داده شده:

  • نام و لوگوی برنامه
  • توضیحات برنامه
  • محدوده‌های دسترسی درخواستی
  • دکمه‌های تأیید/لغو

3. تصمیم کاربر:

  • تأیید: ادامه فرآیند OAuth
  • لغو: بازگشت به برنامه اصلی

📡 API Documentation

Base URL

https://your-domain.com/oauth

1. Authorization Endpoint

درخواست مجوز:

GET /oauth/authorize

پارامترهای مورد نیاز:

{
  "response_type": "code",
  "client_id": "mL0qT1fkIL6MCJfxIPAh7nM2cQ7ykxEy",
  "redirect_uri": "https://your-app.com/callback",
  "scope": "read_profile read_business",
  "state": "random_string_for_csrf"
}

پاسخ موفق:

HTTP/1.1 302 Found
Location: https://your-app.com/callback?code=AUTHORIZATION_CODE&state=random_string

2. Token Endpoint

درخواست Access Token:

POST /oauth/token
Content-Type: application/x-www-form-urlencoded

پارامترهای مورد نیاز:

{
  "grant_type": "authorization_code",
  "client_id": "mL0qT1fkIL6MCJfxIPAh7nM2cQ7ykxEy",
  "client_secret": "goM7latD9akY83z2O2e9IIEYED3Re6sRMd36f5cUSYHm389PPSqYbFHSX8GtQ9H1",
  "code": "AUTHORIZATION_CODE",
  "redirect_uri": "https://your-app.com/callback"
}

پاسخ موفق:

{
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "def50200...",
  "scope": "read_profile read_business"
}

3. User Info Endpoint

درخواست اطلاعات کاربر:

GET /oauth/userinfo
Authorization: Bearer ACCESS_TOKEN

پاسخ موفق:

{
  "id": 123,
  "email": "user@example.com",
  "name": "نام کاربر",
  "profile": {
    "phone": "+989123456789",
    "address": "تهران، ایران"
  }
}

4. Refresh Token Endpoint

تمدید Access Token:

POST /oauth/token
Content-Type: application/x-www-form-urlencoded

پارامترهای مورد نیاز:

{
  "grant_type": "refresh_token",
  "client_id": "mL0qT1fkIL6MCJfxIPAh7nM2cQ7ykxEy",
  "client_secret": "goM7latD9akY83z2O2e9IIEYED3Re6sRMd36f5cUSYHm389PPSqYbFHSX8GtQ9H1",
  "refresh_token": "def50200..."
}

5. Revoke Endpoint

لغو Token:

POST /oauth/revoke
Authorization: Bearer ACCESS_TOKEN

پارامترهای مورد نیاز:

{
  "token": "ACCESS_TOKEN_OR_REFRESH_TOKEN"
}

6. Discovery Endpoint

دریافت اطلاعات OAuth Server:

GET /.well-known/oauth-authorization-server

پاسخ:

{
  "issuer": "https://hesabix.ir",
  "authorization_endpoint": "https://hesabix.ir/oauth/authorize",
  "token_endpoint": "https://hesabix.ir/oauth/token",
  "userinfo_endpoint": "https://hesabix.ir/oauth/userinfo",
  "revocation_endpoint": "https://hesabix.ir/oauth/revoke",
  "response_types_supported": ["code"],
  "grant_types_supported": ["authorization_code", "refresh_token"],
  "token_endpoint_auth_methods_supported": ["client_secret_post"],
  "scopes_supported": [
    "read_profile",
    "write_profile",
    "read_business",
    "write_business",
    "read_financial",
    "write_financial",
    "read_contacts",
    "write_contacts",
    "read_documents",
    "write_documents",
    "admin_access"
  ]
}

🔗 نحوه اتصال

1. ثبت برنامه

ابتدا برنامه خود را در بخش مدیریت ثبت کنید:

// اطلاعات مورد نیاز
const appInfo = {
  name: "My Application",
  description: "توضیح برنامه من",
  website: "https://myapp.com",
  redirectUri: "https://myapp.com/oauth/callback",
  allowedScopes: ["read_profile", "read_business"],
  ipWhitelist: ["192.168.1.0/24"], // اختیاری
  rateLimit: 1000
};

2. پیاده‌سازی OAuth Flow

مرحله 1: درخواست مجوز

function initiateOAuth() {
  const params = new URLSearchParams({
    response_type: 'code',
    client_id: 'YOUR_CLIENT_ID',
    redirect_uri: 'https://myapp.com/oauth/callback',
    scope: 'read_profile read_business',
    state: generateRandomString()
  });
  
  window.location.href = `https://hesabix.com/oauth/authorize?${params}`;
}

مرحله 2: دریافت Authorization Code

// در callback URL
function handleCallback() {
  const urlParams = new URLSearchParams(window.location.search);
  const code = urlParams.get('code');
  const state = urlParams.get('state');
  
  if (code && state) {
    exchangeCodeForToken(code);
  }
}

مرحله 3: تبدیل Code به Token

async function exchangeCodeForToken(code) {
  const response = await fetch('https://hesabix.com/oauth/token', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
    },
    body: new URLSearchParams({
      grant_type: 'authorization_code',
      client_id: 'YOUR_CLIENT_ID',
      client_secret: 'YOUR_CLIENT_SECRET',
      code: code,
      redirect_uri: 'https://myapp.com/oauth/callback'
    })
  });
  
  const tokenData = await response.json();
  // ذخیره token
  localStorage.setItem('access_token', tokenData.access_token);
  localStorage.setItem('refresh_token', tokenData.refresh_token);
}

مرحله 4: استفاده از Access Token

async function getUserInfo() {
  const response = await fetch('https://hesabix.com/oauth/userinfo', {
    headers: {
      'Authorization': `Bearer ${localStorage.getItem('access_token')}`
    }
  });
  
  const userData = await response.json();
  return userData;
}

3. مدیریت Token

تمدید Access Token:

async function refreshAccessToken() {
  const response = await fetch('https://hesabix.com/oauth/token', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
    },
    body: new URLSearchParams({
      grant_type: 'refresh_token',
      client_id: 'YOUR_CLIENT_ID',
      client_secret: 'YOUR_CLIENT_SECRET',
      refresh_token: localStorage.getItem('refresh_token')
    })
  });
  
  const tokenData = await response.json();
  localStorage.setItem('access_token', tokenData.access_token);
  localStorage.setItem('refresh_token', tokenData.refresh_token);
}

لغو Token:

async function revokeToken() {
  await fetch('https://hesabix.com/oauth/revoke', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${localStorage.getItem('access_token')}`
    },
    body: JSON.stringify({
      token: localStorage.getItem('access_token')
    })
  });
  
  localStorage.removeItem('access_token');
  localStorage.removeItem('refresh_token');
}

🔒 امنیت

1. محدودیت‌های IP

// بررسی IP در backend
function checkIpWhitelist($clientIp, $whitelist) {
  if (empty($whitelist)) {
    return true; // همه IP ها مجاز
  }
  
  foreach ($whitelist as $allowedIp) {
    if (ipInRange($clientIp, $allowedIp)) {
      return true;
    }
  }
  
  return false;
}

2. محدودیت‌های Scope

// بررسی دسترسی در backend
function checkScope($requestedScope, $allowedScopes) {
  $requestedScopes = explode(' ', $requestedScope);
  
  foreach ($requestedScopes as $scope) {
    if (!in_array($scope, $allowedScopes)) {
      return false;
    }
  }
  
  return true;
}

3. Rate Limiting

// محدودیت درخواست
function checkRateLimit($clientId, $limit) {
  $requests = getRequestCount($clientId, '1 hour');
  return $requests < $limit;
}

4. Token Security

  • Access Token: عمر 1 ساعت
  • Refresh Token: عمر 30 روز
  • JWT Signature: امضای دیجیتال
  • Token Revocation: امکان لغو فوری

5. نکات امنیتی مهم

  1. HTTPS اجباری: تمام ارتباطات باید روی HTTPS باشد
  2. State Parameter: همیشه از state parameter استفاده کنید
  3. Client Secret: Client Secret را در کد سمت کلاینت قرار ندهید
  4. Token Storage: توکن‌ها را در جای امنی ذخیره کنید
  5. Scope Validation: همیشه scope ها را بررسی کنید

💻 مثال‌های عملی

مثال 1: اپلیکیشن وب

<!DOCTYPE html>
<html>
<head>
    <title>OAuth Example</title>
</head>
<body>
    <button onclick="login()">ورود با Hesabix</button>
    
    <script>
        const CLIENT_ID = 'YOUR_CLIENT_ID';
        const REDIRECT_URI = 'https://myapp.com/callback';
        
        function login() {
            const params = new URLSearchParams({
                response_type: 'code',
                client_id: CLIENT_ID,
                redirect_uri: REDIRECT_URI,
                scope: 'read_profile',
                state: Math.random().toString(36)
            });
            
            window.location.href = `https://hesabix.com/oauth/authorize?${params}`;
        }
        
        // بررسی callback
        if (window.location.search.includes('code=')) {
            handleCallback();
        }
        
        async function handleCallback() {
            const code = new URLSearchParams(window.location.search).get('code');
            
            const response = await fetch('https://hesabix.com/oauth/token', {
                method: 'POST',
                headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                body: new URLSearchParams({
                    grant_type: 'authorization_code',
                    client_id: CLIENT_ID,
                    client_secret: 'YOUR_CLIENT_SECRET',
                    code: code,
                    redirect_uri: REDIRECT_URI
                })
            });
            
            const data = await response.json();
            console.log('Token received:', data);
        }
    </script>
</body>
</html>

مثال 2: اپلیکیشن موبایل

// React Native Example
import { Linking } from 'react-native';

class OAuthManager {
  constructor() {
    this.clientId = 'YOUR_CLIENT_ID';
    this.redirectUri = 'myapp://oauth/callback';
  }
  
  async login() {
    const authUrl = `https://hesabix.com/oauth/authorize?` +
      `response_type=code&` +
      `client_id=${this.clientId}&` +
      `redirect_uri=${encodeURIComponent(this.redirectUri)}&` +
      `scope=read_profile&` +
      `state=${Math.random().toString(36)}`;
    
    await Linking.openURL(authUrl);
  }
  
  async handleCallback(url) {
    const code = url.match(/code=([^&]*)/)?.[1];
    if (code) {
      await this.exchangeCodeForToken(code);
    }
  }
  
  async exchangeCodeForToken(code) {
    const response = await fetch('https://hesabix.com/oauth/token', {
      method: 'POST',
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      body: new URLSearchParams({
        grant_type: 'authorization_code',
        client_id: this.clientId,
        client_secret: 'YOUR_CLIENT_SECRET',
        code: code,
        redirect_uri: this.redirectUri
      })
    });
    
    const data = await response.json();
    await AsyncStorage.setItem('access_token', data.access_token);
  }
}

مثال 3: اپلیکیشن سرور

# Python Flask Example
from flask import Flask, request, redirect, session
import requests

app = Flask(__name__)
app.secret_key = 'your-secret-key'

CLIENT_ID = 'YOUR_CLIENT_ID'
CLIENT_SECRET = 'YOUR_CLIENT_SECRET'
REDIRECT_URI = 'https://myapp.com/oauth/callback'

@app.route('/login')
def login():
    auth_url = f'https://hesabix.com/oauth/authorize?' + \
               f'response_type=code&' + \
               f'client_id={CLIENT_ID}&' + \
               f'redirect_uri={REDIRECT_URI}&' + \
               f'scope=read_profile'
    
    return redirect(auth_url)

@app.route('/oauth/callback')
def callback():
    code = request.args.get('code')
    
    # تبدیل code به token
    token_response = requests.post('https://hesabix.com/oauth/token', data={
        'grant_type': 'authorization_code',
        'client_id': CLIENT_ID,
        'client_secret': CLIENT_SECRET,
        'code': code,
        'redirect_uri': REDIRECT_URI
    })
    
    token_data = token_response.json()
    session['access_token'] = token_data['access_token']
    
    return 'Login successful!'

@app.route('/user-info')
def user_info():
    headers = {'Authorization': f"Bearer {session['access_token']}"}
    response = requests.get('https://hesabix.com/oauth/userinfo', headers=headers)
    
    return response.json()

مثال 4: کلاس کامل JavaScript

class HesabixOAuth {
  constructor(clientId, redirectUri) {
    this.clientId = clientId;
    this.redirectUri = redirectUri;
    this.baseUrl = 'https://hesabix.com';
  }

  // شروع فرآیند OAuth
  authorize(scopes = ['read_profile']) {
    const state = this.generateState();
    const params = new URLSearchParams({
      client_id: this.clientId,
      redirect_uri: this.redirectUri,
      response_type: 'code',
      scope: scopes.join(' '),
      state: state
    });
    
    localStorage.setItem('oauth_state', state);
    window.location.href = `${this.baseUrl}/oauth/authorize?${params}`;
  }

  // پردازش callback
  async handleCallback() {
    const urlParams = new URLSearchParams(window.location.search);
    const code = urlParams.get('code');
    const state = urlParams.get('state');
    const savedState = localStorage.getItem('oauth_state');

    if (state !== savedState) {
      throw new Error('State mismatch');
    }

    if (!code) {
      throw new Error('Authorization code not found');
    }

    const tokens = await this.exchangeCode(code);
    localStorage.setItem('access_token', tokens.access_token);
    localStorage.setItem('refresh_token', tokens.refresh_token);
    
    return tokens;
  }

  // مبادله کد با توکن
  async exchangeCode(code) {
    const response = await fetch(`${this.baseUrl}/oauth/token`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      },
      body: new URLSearchParams({
        grant_type: 'authorization_code',
        client_id: this.clientId,
        client_secret: 'YOUR_CLIENT_SECRET', // در سرور ذخیره شود
        code: code,
        redirect_uri: this.redirectUri
      })
    });

    if (!response.ok) {
      throw new Error('Token exchange failed');
    }

    return await response.json();
  }

  // دریافت اطلاعات کاربر
  async getUserInfo() {
    const token = localStorage.getItem('access_token');
    const response = await fetch(`${this.baseUrl}/oauth/userinfo`, {
      headers: {
        'Authorization': `Bearer ${token}`
      }
    });

    if (!response.ok) {
      throw new Error('Failed to get user info');
    }

    return await response.json();
  }

  // تمدید توکن
  async refreshToken() {
    const refreshToken = localStorage.getItem('refresh_token');
    const response = await fetch(`${this.baseUrl}/oauth/token`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      },
      body: new URLSearchParams({
        grant_type: 'refresh_token',
        client_id: this.clientId,
        client_secret: 'YOUR_CLIENT_SECRET',
        refresh_token: refreshToken
      })
    });

    if (!response.ok) {
      throw new Error('Token refresh failed');
    }

    const tokens = await response.json();
    localStorage.setItem('access_token', tokens.access_token);
    localStorage.setItem('refresh_token', tokens.refresh_token);
    
    return tokens;
  }

  generateState() {
    return Math.random().toString(36).substring(2, 15);
  }
}

// استفاده
const oauth = new HesabixOAuth('YOUR_CLIENT_ID', 'https://yourapp.com/callback');

// شروع OAuth
oauth.authorize(['read_profile', 'read_business']);

// در صفحه callback
oauth.handleCallback().then(tokens => {
  console.log('OAuth successful:', tokens);
  // دریافت اطلاعات کاربر
  return oauth.getUserInfo();
}).then(userInfo => {
  console.log('User info:', userInfo);
});

🔧 عیب‌یابی

خطاهای رایج:

1. invalid_client

علت: Client ID یا Secret اشتباه راه حل: بررسی صحت Client ID و Secret

2. invalid_grant

علت: Authorization Code نامعتبر یا منقضی شده راه حل: درخواست مجدد Authorization Code

3. invalid_scope

علت: Scope درخواستی مجاز نیست راه حل: بررسی Scope های مجاز در پنل مدیریت

4. access_denied

علت: کاربر دسترسی را لغو کرده راه حل: درخواست مجدد از کاربر

5. server_error

علت: خطای سرور راه حل: بررسی لاگ‌های سرور

کدهای خطا:

const errorCodes = {
  'invalid_request': 'درخواست نامعتبر',
  'invalid_client': 'Client ID یا Secret اشتباه',
  'invalid_grant': 'کد مجوز نامعتبر',
  'unauthorized_client': 'برنامه مجاز نیست',
  'unsupported_grant_type': 'نوع grant پشتیبانی نمی‌شود',
  'invalid_scope': 'Scope نامعتبر',
  'access_denied': 'دسترسی رد شد',
  'server_error': 'خطای سرور',
  'temporarily_unavailable': 'سرویس موقتاً در دسترس نیست'
};

لاگ‌ها:

# مشاهده لاگ‌های OAuth
tail -f /var/log/hesabix/oauth.log

# پاک کردن کش
php bin/console cache:clear

# بررسی وضعیت سرور
php bin/console debug:router | grep oauth

📞 پشتیبانی

اطلاعات تماس:

  • ایمیل: support@hesabix.com
  • تلفن: 021-12345678
  • ساعات کاری: شنبه تا چهارشنبه، 9 صبح تا 6 عصر
  • تلگرام: @hesabix_support

سوالات متداول:

Q: چگونه Client Secret را تغییر دهم؟

A: در پنل مدیریت، روی منوی سه نقطه برنامه کلیک کرده و "بازسازی کلید" را انتخاب کنید.

Q: آیا می‌توانم چندین Redirect URI داشته باشم؟

A: خیر، هر برنامه فقط یک Redirect URI می‌تواند داشته باشد.

Q: توکن‌ها چه مدت اعتبار دارند؟

A: Access Token 1 ساعت و Refresh Token 30 روز اعتبار دارد.

Q: چگونه IP Whitelist را تنظیم کنم؟

A: در زمان ایجاد یا ویرایش برنامه، IP های مجاز را اضافه کنید. اگر خالی باشد، از هر IP مجاز است.

Q: آیا می‌توانم Scope ها را بعداً تغییر دهم؟

A: بله، در بخش ویرایش برنامه می‌توانید Scope ها را تغییر دهید.

گزارش باگ:

برای گزارش باگ، لطفاً اطلاعات زیر را ارسال کنید:

  1. نوع خطا: کد خطا و پیام
  2. مراحل تولید: مراحل دقیق تولید خطا
  3. اطلاعات برنامه: Client ID و نام برنامه
  4. لاگ‌ها: لاگ‌های مربوطه
  5. مرورگر/سیستم عامل: اطلاعات محیط اجرا

📚 منابع بیشتر


📋 چک‌لیست پیاده‌سازی

قبل از شروع:

  • برنامه در پنل مدیریت ثبت شده
  • Client ID و Secret دریافت شده
  • Redirect URI تنظیم شده
  • Scope های مورد نیاز تعیین شده
  • IP Whitelist تنظیم شده (در صورت نیاز)

پیاده‌سازی:

  • Authorization Request پیاده‌سازی شده
  • Callback Handler پیاده‌سازی شده
  • Token Exchange پیاده‌سازی شده
  • Error Handling پیاده‌سازی شده
  • Token Storage پیاده‌سازی شده

تست:

  • Authorization Flow تست شده
  • Token Exchange تست شده
  • User Info API تست شده
  • Error Scenarios تست شده
  • Security Features تست شده

نسخه مستندات: 1.0
تاریخ آخرین به‌روزرسانی: 2025-08-16
وضعیت: فعال
توسعه‌دهنده: Hesabix Team