OIDC Check Session Iframe — Cross-Application Session State Monitoring
In this tutorial, you will learn about OIDC Check Session Iframe. We cover key concepts, practical examples, and best practices to help you master this topic.
The check_session_iframe is a hidden iframe hosted by the OIDC provider that client applications use to query the current session state via postMessage, enabling real-time session monitoring across multiple applications.
What You'll Learn
- How the check_session_iframe enables cross-application session monitoring
- How to implement postMessage-based session state queries
- How to handle session state changes in your application
Why It Matters
When a user logs out of one application or the provider terminates their session, other applications need to know immediately. Without the check_session_iframe, each app would need its own polling mechanism against the provider's API, creating load and complexity.
Real-World Use
DodaMail, DodaDrive, and DodaCalendar all embed the same check_session_iframe from the provider. When the user's session expires, all three applications detect the change within 30 seconds and gracefully redirect to the login page without the user seeing stale data.
flowchart LR
subgraph Browser
I["Check Session Iframe\nhttps://accounts.example.com/check_session"]
A1["DodaMail\nApp Iframe"]
A2["DodaDrive\nApp Iframe"]
end
I <-->|"postMessage"| A1
I <-->|"postMessage"| A2
I -->|"Client ID + Session State"| P["Provider Session\nRegistry"]
P -->|"Changed / Unchanged"| I
style I fill:#dbeafe,stroke:#2563eb
style P fill:#fef3c7,stroke:#d97706
Loading the Iframe
<!-- Load the check session iframe (hidden) -->
<iframe id="op-check-session-iframe"
src="https://accounts.example.com/check_session"
style="display: none; position: absolute; width: 0; height: 0;"
sandbox="allow-scripts allow-same-origin">
</iframe>
Implementing Session Monitoring
class SessionMonitor {
constructor(providerOrigin, clientId, checkIntervalMs = 30000) {
this.providerOrigin = providerOrigin;
this.clientId = clientId;
this.checkIntervalMs = checkIntervalMs;
this.sessionState = sessionStorage.getItem('oidc_session_state');
this.timer = null;
window.addEventListener('message', this.handleMessage.bind(this));
}
start() {
if (!this.sessionState) {
console.warn('No session state to monitor');
return;
}
// Initial check after iframe loads
setTimeout(() => this.check(), 2000);
// Periodic check
this.timer = setInterval(() => this.check(), this.checkIntervalMs);
}
stop() {
if (this.timer) {
clearInterval(this.timer);
this.timer = null;
}
}
check() {
const iframe = document.getElementById('op-check-session-iframe');
if (!iframe || !iframe.contentWindow) return;
const message = `${this.clientId} ${this.sessionState}`;
iframe.contentWindow.postMessage(message, this.providerOrigin);
}
handleMessage(event) {
// CRITICAL: Validate message origin
if (event.origin !== this.providerOrigin) {
console.warn('Ignoring message from untrusted origin:', event.origin);
return;
}
if (event.data === 'unchanged') {
console.log('Session still active');
this.dispatchEvent('session-active');
} else if (event.data === 'changed') {
console.log('Session state changed or ended');
this.sessionState = null;
sessionStorage.removeItem('oidc_session_state');
this.dispatchEvent('session-ended');
this.stop();
}
}
dispatchEvent(name) {
document.dispatchEvent(new CustomEvent(name));
}
}
// Usage
const monitor = new SessionMonitor(
'https://accounts.example.com',
'doda-browser'
);
document.addEventListener('session-ended', () => {
// Redirect to login or show overlay
window.location.href = '/login?reason=session_expired';
});
monitor.start();
Server-Side Validation
The check_session_iframe result should be validated server-side before performing sensitive operations:
from flask import Flask, session, jsonify, request
import requests
app = Flask(__name__)
@app.route('/api/sensitive-action')
def sensitive_action():
access_token = session.get('access_token')
if not access_token:
return jsonify({"error": "not_authenticated"}), 401
# Server-side session verification
introspect_response = requests.post(
"https://accounts.example.com/introspect",
data={"token": access_token},
auth=("doda-browser", "client-secret")
)
token_data = introspect_response.json()
if not token_data.get('active'):
return jsonify({
"error": "session_expired",
"message": "Your session has expired. Please log in again."
}), 401
return jsonify({"data": "sensitive data here"})
Common Mistakes
1. Not Validating postMessage Origin
Any website can send messages to your window. Always validate event.origin matches the provider's origin to prevent spoofing.
2. Checking Too Frequently
Every check sends a postMessage and potentially queries the provider's session store. 30-second intervals balance responsiveness with load.
3. Relying Only on Client-Side Check
The check_session_iframe result is not cryptographically signed. Use server-side token introspection for security-critical decisions.
4. Not Handling Iframe Load Failures
If the iframe fails to load (blocked, network error), the monitor silently breaks. Add error handling and fallback polling.
5. Forgetting to Stop Monitoring on Logout
When the user logs out, stop the monitoring timer to prevent errors from the now-invalid session state.
Practice Questions
- What transport mechanism does check_session_iframe use?
- Why must you validate event.origin in the message handler?
- What are the two possible responses from the iframe?
- How often should you poll the iframe for changes?
- What should you do when the session state changes to changed?
Answers
- HTML5 postMessage between Windows/iframes. 2. To prevent spoofed messages from untrusted origins. 3.
unchanged(session still active) orchanged(session ended). 4. Every 30 seconds is a good balance. 5. Redirect to login, clear local session, and stop monitoring.
Challenge
Build a session monitor that uses the check_session_iframe for four concurrent OIDC applications, displays their session states in a dashboard, and triggers a coordinated redirect to a single login page when any session ends.
FAQ
Mini Project
Build a session monitoring dashboard that embeds a provider's check_session_iframe, monitors session states for three simulated applications, displays real-time status indicators, logs state changes with timestamps, and provides a manual session refresh button.
What's Next
- Learn about front-channel logout for browser-based session termination
- Explore back-channel logout for server-to-server logout notifications
- Continue to post-logout redirect URIs for user experience after logout
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro