مقدمه
در مقاله قبلی درباره پیادهسازی SSO چنداپلیکیشنی با OpenID Connect در PHP دیدیم که چگونه میتوان چند Application را به یک Identity Provider مرکزی متصل کرد.
برای مثال:
auth.example.com
│
├── portal.example.com
├── shop.example.com
└── admin.example.com
کاربر یک بار در Identity Provider وارد میشود و سپس میتواند بدون وارد کردن دوباره رمز عبور، به Applicationهای مختلف دسترسی داشته باشد.
اما یک سؤال مهم باقی میماند:
وقتی کاربر روی Logout کلیک میکند، دقیقاً چه اتفاقی باید بیفتد؟
آیا فقط Session همان Application حذف شود؟
یا Session مربوط به Identity Provider هم باید از بین برود؟
اگر کاربر از Portal خارج شود، آیا باید از Shop و Admin هم خارج شود؟
اگر فقط Session محلی Portal حذف شود، چرا وقتی دوباره روی Login کلیک میکند بدون وارد کردن رمز عبور وارد میشود؟
پاسخ این سؤالات ما را به مفهوم RP-Initiated Logout در OpenID Connect میرساند.
در این مقاله با PHP، Session، id_token_hint، post_logout_redirect_uri و معماری Logout در سیستمهای چنداپلیکیشنی آشنا میشویم.
# RP-Initiated Logout چیست؟
RP مخفف:
Relying Party
است.
در معماری OpenID Connect، Applicationهایی که به Identity Provider اعتماد میکنند، معمولاً Relying Party یا RP نامیده میشوند.
بنابراین:
Portal
Shop
Admin
هرکدام میتوانند یک RP باشند.
RP-Initiated Logout یعنی Application تصمیم میگیرد فرآیند Logout را شروع کند و کاربر را برای خروج از Session مرکزی به Identity Provider هدایت میکند.
بهصورت ساده:
User
↓
Portal Logout
↓
Identity Provider Logout
↓
Destroy IdP Session
↓
Return to Portal
# چرا Logout در SSO پیچیده است؟
در یک سایت معمولی ممکن است فقط یک Session داشته باشیم:
Browser
↓
Website
↓
Session
اما در SSO چند Session وجود دارد.
مثلاً:
Browser
│
├── Portal Session
│
├── Shop Session
│
├── Admin Session
│
└── Identity Provider Session
بنابراین Logout باید مشخص کند کدام Sessionها قرار است از بین بروند.
# Session محلی با Session مرکزی متفاوت است
فرض کنیم کاربر وارد Portal شده است.
portal.example.com
Portal یک Session محلی ایجاد میکند:
Portal Session
همزمان Identity Provider نیز Session خودش را دارد:
IdP Session
پس:
Portal Session
≠
IdP Session
اگر فقط Portal Session را حذف کنیم:
Portal Session → Destroyed
IdP Session → Still Active
در این حالت کاربر از Portal خارج شده است، اما هنوز در Identity Provider Login است.
# یک مثال واقعی
فرض کنید کاربر ابتدا وارد Portal میشود:
portal.example.com
سپس:
Portal
↓
auth.example.com
↓
Login
بعد از Login:
IdP Session = Active
Portal Session = Active
حالا کاربر روی Logout کلیک میکند.
اگر فقط این کار را انجام دهیم:
session_destroy();
نتیجه:
IdP Session = Active
Portal Session = Destroyed
حالا اگر کاربر دوباره روی Login کلیک کند:
Portal
↓
Identity Provider
↓
Existing IdP Session
↓
Login بدون درخواست Password
ممکن است کاربر تصور کند Logout کار نکرده است.
در واقع Logout محلی انجام شده، اما Logout مرکزی انجام نشده است.
# معماری صحیح Logout
در یک معماری SSO معمولاً میتوانیم فرآیند را به این شکل طراحی کنیم:
User
↓
Application Logout
↓
Destroy Local Session
↓
Redirect to Identity Provider
↓
Identity Provider Logout
↓
Destroy IdP Session
↓
Redirect back to Application
البته ترتیب دقیق مراحل میتواند بر اساس معماری Application و Provider متفاوت باشد.
# Endpoint خروج در OpenID Connect
Identity Provider میتواند یک Logout Endpoint داشته باشد.
مثلاً:
https://auth.example.com/logout
Application کاربر را به این Endpoint هدایت میکند.
اما معمولاً اطلاعات بیشتری نیز باید ارسال شود.
از جمله:
id_token_hint
post_logout_redirect_uri
state
# id_token_hint چیست؟
یکی از پارامترهای مهم در RP-Initiated Logout:
id_token_hint
است.
این مقدار معمولاً یک ID Token مربوط به Session احراز هویت کاربر است.
Application با ارسال آن به Logout Endpoint میتواند اطلاعات لازم درباره Session یا Identity مربوط به Logout را در اختیار Identity Provider قرار دهد.
مثلاً:
https://auth.example.com/logout
?id_token_hint=...
البته Identity Provider باید از RP-Initiated Logout پشتیبانی کند.
# چرا ID Token را برای Logout استفاده میکنیم؟
ID Token قبلاً هنگام Login صادر شده است.
مثلاً:
{
"iss": "https://auth.example.com",
"sub": "123456",
"aud": "portal-web",
"exp": 1780003600
}
Identity Provider با بررسی آن میتواند اطلاعات لازم برای تشخیص Session مربوط به کاربر را داشته باشد.
نکته مهم این است که Application نباید صرفاً هر JWT دلخواهی را به عنوان id_token_hint ارسال کند.
# post_logout_redirect_uri چیست؟
بعد از Logout، Identity Provider باید بداند کاربر را به کجا برگرداند.
برای مثال:
https://portal.example.com/logout/callback
این آدرس با پارامتر:
post_logout_redirect_uri
ارسال میشود.
مثلاً:
https://auth.example.com/logout
?id_token_hint=...
&post_logout_redirect_uri=https://portal.example.com/logout/callback
# آیا میتوان هر Redirect URI را ارسال کرد؟
خیر.
این یکی از مهمترین نکات امنیتی Logout است.
اگر Identity Provider اجازه دهد Application هر URL دلخواهی ارسال کند، مهاجم میتواند از آن برای Redirect کردن کاربر به سایت خودش استفاده کند.
بنابراین Logout Redirect URI نیز باید مانند Login Redirect URI مدیریت شود.
مثلاً در تنظیمات Client:
Allowed Post Logout Redirect URIs
قرار میدهیم:
https://portal.example.com/logout/callback
و فقط URIهای ثبتشده را قبول میکنیم.
# state در Logout
در RP-Initiated Logout میتوان از:
state
نیز استفاده کرد.
برای مثال:
$state = bin2hex(random_bytes(32));
$_SESSION['logout_state'] = $state;
سپس:
state=...
به Logout Endpoint ارسال میشود.
بعد از برگشت کاربر میتوانیم State را بررسی کنیم.
# ساخت Logout در PHP
فرض کنیم Application ما:
portal.example.com
است.
ابتدا Session را شروع میکنیم:
<?php
session_start();
سپس Logout State ایجاد میکنیم:
$state = bin2hex(random_bytes(32));
$_SESSION['logout_state'] = $state;
# نگهداری ID Token
بعد از Login، Application باید در صورت نیاز بتواند ID Token را برای Logout در دسترس داشته باشد.
مثلاً:
$_SESSION['id_token'] = $tokens['id_token'];
البته نحوه نگهداری Token باید با توجه به معماری و مدل تهدید انتخاب شود.
در Applicationهای Server-Side بهتر است Tokenها تا حد امکان از دسترس مستقیم مرورگر خارج باشند.
# ساخت Logout URL
مثلاً:
$idToken = $_SESSION['id_token'] ?? null;
$logoutParams = [
'post_logout_redirect_uri' =>
'https://portal.example.com/logout/callback',
'state' => $state,
];
if ($idToken) {
$logoutParams['id_token_hint'] = $idToken;
}
$logoutUrl =
'https://auth.example.com/logout?' .
http_build_query($logoutParams);
header('Location: ' . $logoutUrl);
exit;
این کد یک نمونه آموزشی است و در پروژه Production باید Endpointها، Redirect URIها و اعتبار Tokenها مطابق Provider واقعی مدیریت شوند.
# آیا باید قبل از Redirect Session را Destroy کنیم؟
این موضوع به طراحی Application بستگی دارد.
اگر Session را بلافاصله Destroy کنیم، ممکن است اطلاعات موردنیاز برای تکمیل فرآیند Logout را از دست بدهیم.
به همین دلیل بهتر است فرآیند Logout را بهصورت مشخص طراحی کنیم.
یک روش میتواند این باشد:
Logout Request
↓
Create Logout State
↓
Keep Required OIDC Data
↓
Redirect to IdP
↓
IdP Logout
↓
Return to Logout Callback
↓
Destroy Local Session
روش دقیق به معماری Session و نیازهای Application بستگی دارد.
# Logout Callback
مثلاً:
https://portal.example.com/logout/callback
در این Endpoint:
<?php
session_start();
if (!isset($_GET['state'])) {
http_response_code(400);
exit('Invalid logout response.');
}
سپس State را بررسی میکنیم:
if (!hash_equals(
$_SESSION['logout_state'] ?? '',
$_GET['state']
)) {
http_response_code(400);
exit('Invalid logout state.');
}
بعد از تأیید:
session_unset();
session_destroy();
و کاربر به صفحه عمومی هدایت میشود:
header('Location: /');
exit;
# فرآیند کامل Logout
در نهایت:
Browser
│
▼
┌─────────────────┐
│ Portal Logout │
└────────┬────────┘
│
▼
Generate state
│
▼
Identity Provider
│
▼
Destroy IdP
Session
│
▼
Logout Callback
│
▼
Destroy Local Session
│
▼
Portal
# اگر کاربر از Shop خارج شود چه؟
فرض کنیم:
shop.example.com
هم یک OIDC Client است.
Shop نیز Logout Endpoint خودش را دارد.
بنابراین:
Shop
↓
IdP Logout
↓
Shop Logout Callback
Applicationها میتوانند Client IDهای متفاوت داشته باشند:
portal-web
shop-web
admin-web
اما همه آنها از Identity Provider مشترک استفاده میکنند.
# آیا Logout از یک Application باید همه Applicationها را Logout کند؟
این موضوع به نیاز معماری بستگی دارد.
دو سناریوی متفاوت داریم.
سناریو اول: Local Logout
کاربر فقط از همان Application خارج میشود.
Portal Logout
↓
Portal Session Destroyed
اما Session مرکزی Identity Provider همچنان فعال است.
در این حالت Login مجدد به Portal ممکن است بدون وارد کردن رمز انجام شود.
سناریو دوم: Global Logout
کاربر میخواهد از سیستم مرکزی نیز خارج شود.
Portal Logout
↓
IdP Logout
↓
Central Session Destroyed
در این حالت Applicationهای دیگر نیز در فرآیند Logout مرکزی قرار میگیرند؛ بسته به اینکه Provider و سایر RPها چه مکانیزم Logoutی را پیادهسازی کرده باشند.
# Local Logout و SSO Logout
بهتر است این دو مفهوم را در UI نیز از هم تفکیک کنیم.
مثلاً:
خروج از این برنامه
در مقابل:
خروج از همه حسابها
اما اینکه دقیقاً چنین تفکیکی را در محصول ارائه کنید به معماری و نیاز کسبوکار بستگی دارد.
# Logout و Browser Session
یکی از نکات مهم این است که Logout فقط حذف یک متغیر PHP نیست.
ممکن است Sessionهای مختلفی وجود داشته باشند:
Application Cookie
Identity Provider Cookie
Refresh Token
Access Token
Session Database Record
بنابراین باید مشخص کنیم هر کدام چه زمانی منقضی یا حذف میشوند.
# Access Token بعد از Logout چه میشود؟
فرض کنید کاربر Access Token داشته باشد:
Access Token
Expires in 3600 seconds
اگر فقط Session محلی را Destroy کنیم، ممکن است Access Token تا زمان انقضای خودش معتبر باقی بماند.
بنابراین Logout بهتنهایی الزاماً به معنی بیاعتبار شدن فوری تمام Tokenهای صادرشده نیست.
برای سیستمهای حساس باید سیاست Token Lifecycle مشخص باشد.
# Refresh Token چه میشود؟
Refresh Token معمولاً عمر بیشتری از Access Token دارد.
بنابراین در Logout باید سیاست مشخصی برای آن داشته باشیم.
در معماریهای امن میتوان Refresh Token را:
Revoke
کرد.
بهخصوص اگر کاربر قصد خروج کامل داشته باشد.
# Revocation چیست؟
Revocation یعنی Token دیگر قابل استفاده نباشد.
مثلاً:
Refresh Token
↓
Revoke
↓
Cannot be used anymore
این موضوع با Logout Session متفاوت است.
ممکن است:
Session Destroyed
اما:
Refresh Token
هنوز معتبر باشد.
بنابراین سیستم باید این دو مفهوم را جداگانه مدیریت کند.
# Logout در Identity Provider
Identity Provider باید Session مرکزی کاربر را مدیریت کند.
مثلاً:
oidc_sessions
میتواند اطلاعاتی درباره Sessionهای OIDC داشته باشد.
یک طراحی ساده:
CREATE TABLE oidc_sessions (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT UNSIGNED NOT NULL,
client_id VARCHAR(100) NOT NULL,
session_id VARCHAR(255) NOT NULL,
created_at DATETIME NOT NULL,
expires_at DATETIME NOT NULL
);
در Production ساختار واقعی میتواند بسیار متفاوت و پیچیدهتر باشد.
# ارتباط Logout با SSO
در SSO دو Login داریم:
Central Login
Local Application Login
و به همین ترتیب میتوانیم دو Logout داشته باشیم:
Central Logout
Local Logout
این تفاوت برای طراحی سیستم بسیار مهم است.
# Front-Channel Logout چیست؟
در معماریهای پیشرفتهتر، Identity Provider میتواند Logout را از طریق مرورگر به Applicationهای مختلف اعلام کند.
به این روش:
Front-Channel Logout
گفته میشود.
بهصورت مفهومی:
Identity Provider
│
┌─────────┼─────────┐
▼ ▼ ▼
Portal Shop Admin
│ │ │
Logout Logout Logout
در این حالت Applicationها میتوانند Session محلی خودشان را نیز خاتمه دهند.
# Back-Channel Logout چیست؟
در Back-Channel Logout ارتباط Logout بین Serverها انجام میشود و به مرورگر کاربر وابسته نیست.
بهصورت مفهومی:
Identity Provider
│
├──── Server → Portal
│
├──── Server → Shop
│
└──── Server → Admin
Applicationها بر اساس پیام Logout Session مربوطه را خاتمه میدهند.
این مدل برای معماریهای بزرگ میتواند کاربرد داشته باشد، اما پیادهسازی آن نیازمند طراحی دقیق Session و ارتباطات Server-to-Server است.
# آیا همیشه باید Front-Channel یا Back-Channel داشته باشیم؟
خیر.
برای بسیاری از Applicationها ابتدا میتوان:
Local Logout
+
RP-Initiated Logout
را بهدرستی پیادهسازی کرد.
اگر نیاز به Logout هماهنگ بین تعداد زیادی RP وجود داشته باشد، میتوان مکانیزمهای پیشرفتهتر را بررسی کرد.
# تفاوت RP-Initiated، Front-Channel و Back-Channel
بهصورت خلاصه:
| روش | شروعکننده | مسیر اصلی |
|---|---|---|
| RP-Initiated Logout | Application | Browser → IdP |
| Front-Channel Logout | IdP | Browser → RPها |
| Back-Channel Logout | IdP | Server → RPها |
این روشها میتوانند در یک معماری کامل کنار یکدیگر نیز استفاده شوند.
# جلوگیری از Open Redirect در Logout
یکی از مهمترین آسیبپذیریهای احتمالی، Open Redirect است.
مثلاً مهاجم درخواست زیر را ایجاد کند:
https://auth.example.com/logout
?post_logout_redirect_uri=https://evil.example.com
اگر Identity Provider بدون بررسی کاربر را به این آدرس هدایت کند، یک Open Redirect ایجاد شده است.
راهحل:
Allowed Redirect URIs
باید در سطح Client تعریف شوند.
مثلاً:
portal-web
↓
https://portal.example.com/logout/callback
و فقط همان URL یا URLهای ثبتشده قابل استفاده باشند.
# Logout State را فراموش نکنید
در Logout نیز State میتواند برای ارتباط امن درخواست و پاسخ استفاده شود.
ساخت:
$state = bin2hex(random_bytes(32));
ذخیره:
$_SESSION['logout_state'] = $state;
ارسال:
state=...
و بررسی هنگام برگشت:
if (!hash_equals(
$_SESSION['logout_state'] ?? '',
$_GET['state'] ?? ''
)) {
throw new RuntimeException('Invalid state.');
}
# Session Fixation و Logout
در مقاله Session Hijacking و Session Fixation دیدیم که Session باید بهصورت صحیح مدیریت شود.
بعد از Login:
session_regenerate_id(true);
و هنگام Logout نیز باید Session و اطلاعات احراز هویت بهصورت کامل پاک شوند.
برای مثال:
$_SESSION = [];
if (ini_get('session.use_cookies')) {
$params = session_get_cookie_params();
setcookie(
session_name(),
'',
time() - 42000,
$params['path'],
$params['domain'],
$params['secure'],
$params['httponly']
);
}
session_destroy();
این کد نمونهای آموزشی است و در پروژه واقعی بهتر است Session Management یکپارچه و تستشده داشته باشید.
# Logout و CSRF
Logout از نظر طراحی میتواند رفتار متفاوتی نسبت به عملیات تغییر داده داشته باشد، اما Endpointهای حساس Authentication باید با دقت در برابر درخواستهای ناخواسته طراحی شوند.
بهخصوص اگر Logout باعث:
- Revocation Token
- تغییر وضعیت Session
- حذف اطلاعات
- عملیات حساس دیگر
شود، باید مکانیزم مناسب برای جلوگیری از درخواست ناخواسته در نظر گرفته شود.
# Logout در معماری PHP
میتوانیم Endpointهای زیر را داشته باشیم:
/login
/callback
/logout
/logout/callback
ساختار:
public/
├── login.php
├── callback.php
├── logout.php
└── logout-callback.php
# فایل logout.php
نمونه ساده:
<?php
session_start();
$state = bin2hex(random_bytes(32));
$_SESSION['logout_state'] = $state;
$idToken = $_SESSION['id_token'] ?? null;
$params = [
'post_logout_redirect_uri' =>
'https://portal.example.com/logout-callback.php',
'state' => $state,
];
if ($idToken) {
$params['id_token_hint'] = $idToken;
}
$url = 'https://auth.example.com/logout?' .
http_build_query($params);
header('Location: ' . $url);
exit;
# فایل logout-callback.php
<?php
session_start();
$state = $_GET['state'] ?? '';
if (!hash_equals(
$_SESSION['logout_state'] ?? '',
$state
)) {
http_response_code(400);
exit('Invalid logout state.');
}
$_SESSION = [];
session_destroy();
header('Location: /');
exit;
در پروژه واقعی باید Cookie Session نیز بهصورت کامل منقضی شود و مدیریت خطا، Session State و Provider Response دقیقتر باشد.
# Logout بدون Identity Provider
اگر فقط بخواهیم از Application خارج شویم:
<?php
session_start();
$_SESSION = [];
session_destroy();
header('Location: /');
exit;
در این حالت:
Application Session → Destroyed
IdP Session → ممکن است فعال بماند
پس این Local Logout است، نه الزاماً Global Logout.
# چه زمانی Local Logout کافی است؟
مثلاً یک Application داخلی دارید و کاربر فقط میخواهد Session فعلی آن را ببندد.
در این حالت:
Local Logout
میتواند کافی باشد.
اما اگر کاربر انتظار دارد از کل سیستم خارج شود، باید Logout مرکزی نیز در نظر گرفته شود.
# چه زمانی Global Logout اهمیت بیشتری دارد؟
در سیستمهایی مانند:
Customer Portal
Admin Panel
Billing
Support
CRM
ممکن است خروج کامل کاربر اهمیت بیشتری پیدا کند.
در این شرایط باید دقیقاً مشخص شود:
Logout From Current App
با:
Logout From Identity Provider
چه تفاوتی دارد.
# نکات مهم امنیتی
برای یک پیادهسازی Production این موارد را جدی بگیرید:
1. HTTPS
تمام Endpointهای Authentication و Logout باید روی HTTPS باشند.
2. Redirect URI Allowlist
هیچ Redirect URI دلخواهی را قبول نکنید.
3. State
State را تصادفی و غیرقابل حدس ایجاد کنید.
4. ID Token Validation
به id_token_hint صرفاً بهعنوان یک رشته اعتماد نکنید.
5. Session Security
Cookieهای Session را با:
Secure
HttpOnly
SameSite
تنظیم کنید.
6. Token Revocation
برای Refresh Tokenها سیاست مشخصی داشته باشید.
7. Token Logging
Tokenها را در Log ذخیره نکنید.
8. Session Cleanup
بعد از Logout اطلاعات Session را واقعاً پاک کنید.
9. Key Rotation
Identity Provider باید از Key Rotation و JWKS بهصورت صحیح پشتیبانی کند.
10. Logout را تست کنید
سناریوهای مختلف را تست کنید:
Login → Logout
Login → Local Logout
Login → Global Logout
Login → Logout → Login
Multiple Apps → Logout
Expired Session → Logout
Expired ID Token → Logout
Invalid State → Logout
Invalid Redirect URI → Logout
# چکلیست نهایی RP-Initiated Logout
[ ] Identity Provider دارای Logout Endpoint است
[ ] RP-Initiated Logout پشتیبانی میشود
[ ] id_token_hint بهدرستی مدیریت میشود
[ ] post_logout_redirect_uri Allowlist شده است
[ ] state تولید میشود
[ ] state هنگام Callback بررسی میشود
[ ] Local Session حذف میشود
[ ] Session Cookie منقضی میشود
[ ] Refresh Tokenها سیاست Revocation دارند
[ ] HTTPS فعال است
[ ] Open Redirect وجود ندارد
[ ] Tokenها Log نمیشوند
[ ] Logout چند Application تست شده است
[ ] Session مرکزی IdP تست شده است
[ ] Expired Tokenها تست شدهاند
[ ] Invalid State تست شده است
# سوالات متداول
آیا Logout معمولی PHP همان OIDC Logout است؟
خیر.
session_destroy() فقط Session مربوط به همان Application را مدیریت میکند. برای Logout مرکزی باید Identity Provider نیز در فرآیند Logout قرار بگیرد.
id_token_hint چیست؟
id_token_hint معمولاً ID Token مربوط به Session احراز هویت کاربر است که در RP-Initiated Logout به Identity Provider ارسال میشود تا اطلاعات لازم برای شناسایی Session در اختیار Provider قرار گیرد.
post_logout_redirect_uri چه کاربردی دارد؟
مشخص میکند پس از پایان فرآیند Logout، کاربر به چه URL مجازی مجاز بازگردانده شود.
آیا post_logout_redirect_uri میتواند هر URLای باشد؟
خیر. باید توسط Identity Provider و برای Client مربوطه Allowlist شود.
اگر فقط Session سایت را Destroy کنیم چه میشود؟
Session همان سایت از بین میرود، اما Session مربوط به Identity Provider ممکن است همچنان فعال باشد.
آیا Logout باعث Invalid شدن Access Token میشود؟
الزاماً نه. Token Lifecycle مستقل از Session است و باید سیاست انقضا و Revocation مناسب برای Tokenها طراحی شود.
آیا برای هر Application باید Logout Endpoint جدا داشته باشیم؟
هر Application باید بتواند Session محلی خودش را مدیریت کند. همچنین اگر از RP-Initiated Logout استفاده میکند، باید Callback و تنظیمات لازم برای ارتباط با Identity Provider داشته باشد.
# جمعبندی
در معماری SSO، Logout به اندازه Login اهمیت دارد.
چون ما با چند Session مختلف روبهرو هستیم:
Application Session
Identity Provider Session
Access Token
Refresh Token
بنابراین باید مشخص کنیم Logout دقیقاً چه چیزی را خاتمه میدهد.
در RP-Initiated Logout، Application فرآیند Logout را آغاز میکند و کاربر را به Identity Provider هدایت میکند.
پارامترهای مهمی مانند:
id_token_hint
post_logout_redirect_uri
state
در این فرآیند نقش مهمی دارند.
یک معماری ساده میتواند چنین باشد:
Application
↓
Generate state
↓
Identity Provider Logout
↓
Destroy IdP Session
↓
Logout Callback
↓
Destroy Local Session
↓
Logged Out
در معماریهای بزرگتر نیز میتوان Front-Channel Logout یا Back-Channel Logout را برای هماهنگسازی Logout بین چند Application بررسی کرد.
در نهایت، مهمترین اصل این است که Local Logout، Central Logout و Token Revocation را سه مفهوم جداگانه در نظر بگیریم و برای هرکدام سیاست مشخصی داشته باشیم.





