Skip to main content
Glama
skyrmionz

ChatGPT Interactive Components Examples

by skyrmionz
authentication.md11.4 kB
# Example 1: Authentication MCP Server > Session-based authentication with a 3-screen flow **Live URL**: `https://chatgpt-components-0d9232341440.herokuapp.com/mcp` ## Overview This MCP server demonstrates how to build a secure, multi-step authentication flow within ChatGPT. It showcases: - Session management with unique IDs - Multi-screen UI transitions - State persistence across tool calls - Widget-to-server communication ## Demo Flow 1. User: *"Log me into my Target account"* 2. ChatGPT creates a session ID 3. ChatGPT calls authentication tool → widget appears 4. User enters credentials (any work for demo) 5. User enters verification code (any 6 digits) 6. Success screen shows "Welcome Back, Lauren Bailey!" 7. ChatGPT knows user is authenticated as Lauren Bailey ## Architecture ### Tools #### 1. `create-target-session` **Purpose**: Generate a unique session ID for tracking authentication state **Input**: None **Output**: ```json { "sessionId": "sess_1234567890_abc", "message": "Session created" } ``` **Implementation**: ```javascript const sessionId = `sess_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`; authSessions.set(sessionId, { authenticated: false, email: null, name: null, createdAt: Date.now() }); ``` #### 2. `authenticate-target` **Purpose**: Display authentication widget and handle login flow **Input**: - `sessionId` (required): Session ID from `create-target-session` **Output**: - Widget displaying login form OR authenticated confirmation - Text message for ChatGPT **Implementation**: ```javascript const session = authSessions.get(sessionId); if (!session) { return { content: [{ type: 'text', text: 'Invalid session' }], isError: true }; } if (session.authenticated) { // Show success message } else { // Show login widget return { content: [{ type: 'text', text: 'Authentication required' }], widgetData: { html: fs.readFileSync('./widgets/target-auth.html', 'utf8') .replace('{{sessionId}}', sessionId) .replace('{{authenticated}}', 'false') } }; } ``` #### 3. `get-target-auth-status` **Purpose**: Check authentication status without showing widget **Input**: - `sessionId` (required) **Output**: ```json { "authenticated": true, "email": "laurenbailey@gmail.com", "name": "Lauren Bailey" } ``` **Why needed?**: After authentication, ChatGPT needs to retrieve user details without re-displaying the login widget. ### State Management #### Session Storage ```javascript const authSessions = new Map(); // Structure: // sessionId -> { // authenticated: boolean, // email: string | null, // name: string | null, // createdAt: number // } ``` #### Session Cleanup Automatic cleanup prevents memory leaks: ```javascript setInterval(() => { const now = Date.now(); for (const [id, session] of authSessions.entries()) { if (now - session.createdAt > 600000) { // 10 minutes authSessions.delete(id); console.log(`Cleaned up session: ${id}`); } } }, 600000); // Run every 10 minutes ``` ## Widget: target-auth.html ### Screens #### Screen 1: Login ```html <div id="login-screen"> <input type="email" placeholder="Email address" /> <input type="password" placeholder="Password" /> <button id="sign-in-btn">Sign In</button> </div> ``` **Behavior**: - User enters email and password (any credentials work) - Clicks "Sign In" - Transitions to verification screen #### Screen 2: Verification ```html <div id="verification-screen" style="display: none;"> <p>Enter the 6-digit code</p> <div class="code-inputs"> <input maxlength="1" /> <input maxlength="1" /> <input maxlength="1" /> <input maxlength="1" /> <input maxlength="1" /> <input maxlength="1" /> </div> </div> ``` **Behavior**: - Auto-advance inputs as user types - Any 6-digit code works - Calls `/api/session/authenticate` to mark session as authenticated - Transitions to success screen #### Screen 3: Success ```html <div id="success-screen" style="display: none;"> <div class="checkmark">✓</div> <h2>Welcome Back!</h2> <p>Authenticated as Lauren Bailey</p> </div> ``` **Behavior**: - Shows green checkmark animation - Displays hardcoded user name - Calls `window.openai.setWidgetState({ authenticated: true })` ### Key JavaScript Functions #### Transition Between Screens ```javascript function showVerificationScreen() { document.getElementById('login-screen').style.display = 'none'; document.getElementById('verification-screen').style.display = 'flex'; // Focus first input codeInputs[0].focus(); } function showSuccessScreen() { document.getElementById('verification-screen').style.display = 'none'; document.getElementById('success-screen').style.display = 'flex'; } ``` #### Auto-Advancing Code Inputs ```javascript codeInputs.forEach((input, index) => { input.addEventListener('input', (e) => { if (e.target.value.length === 1 && index < codeInputs.length - 1) { codeInputs[index + 1].focus(); // Move to next input } // Check if all 6 digits entered const code = Array.from(codeInputs).map(i => i.value).join(''); if (code.length === 6) { verifyCode(); // Proceed to next screen } }); }); ``` #### Mark Session as Authenticated ```javascript async function markSessionAuthenticated() { const response = await fetch('/api/session/authenticate', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ sessionId: sessionId, email: emailInput.value, name: 'Lauren Bailey' // Hardcoded for demo }) }); const data = await response.json(); if (data.success) { showSuccessScreen(); // Notify ChatGPT if (window.openai?.setWidgetState) { window.openai.setWidgetState({ authenticated: true, email: emailInput.value, name: 'Lauren Bailey', sessionId: sessionId }); } } } ``` ### Dark/Light Mode Support ```javascript // Get theme from ChatGPT if (window.openai?.theme) { window.openai.theme.get().then(theme => { document.body.className = theme; }); window.openai.theme.subscribe(theme => { document.body.className = theme; }); } ``` ```css /* Theme-specific styles */ body.light { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: #333; } body.dark { background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); color: #e0e0e0; } body.light .auth-card { background: white; box-shadow: 0 8px 32px rgba(0,0,0,0.1); } body.dark .auth-card { background: #2a2a3e; box-shadow: 0 8px 32px rgba(0,0,0,0.5); } ``` ## Server Endpoints ### SSE Endpoint: `GET /mcp` Establishes SSE connection for ChatGPT to call tools: ```javascript app.get('/mcp', async (req, res) => { res.setHeader('Content-Type', 'text/event-stream'); res.setHeader('Cache-Control', 'no-cache'); res.setHeader('Connection', 'keep-alive'); res.setHeader('Access-Control-Allow-Origin', '*'); const server = createPizzazServer(); const transport = new SSEServerTransport('/messages', res); await server.connect(transport); sseConnections.set(Date.now().toString(), res); req.on('close', () => { transport.close(); }); }); ``` ### Message Endpoint: `POST /messages` Receives JSON-RPC messages from ChatGPT: ```javascript app.post('/messages', express.text({ type: '*/*' }), (req, res) => { res.setHeader('Access-Control-Allow-Origin', '*'); res.status(200).end(); }); ``` ### Authentication Endpoint: `POST /api/session/authenticate` Called by widget to mark session as authenticated: ```javascript app.post('/api/session/authenticate', express.json(), (req, res) => { res.setHeader('Access-Control-Allow-Origin', '*'); const { sessionId, email, name } = req.body; if (authSessions.has(sessionId)) { authSessions.set(sessionId, { authenticated: true, email: email, name: name, createdAt: authSessions.get(sessionId).createdAt }); res.json({ success: true }); } else { res.status(404).json({ error: 'Session not found' }); } }); ``` ## Usage Examples ### Basic Authentication ``` You: Log me into my Target account ChatGPT: [Creates session, displays login widget] [You enter credentials in widget] ChatGPT: You're now authenticated as Lauren Bailey! ``` ### Check Status ``` You: Am I logged in? ChatGPT: [Calls get-target-auth-status] Yes, you're logged in as Lauren Bailey (laurenbailey@gmail.com) ``` ### Session Expires ``` You: [Wait 10+ minutes] Am I still logged in? ChatGPT: [Calls get-target-auth-status] Your session has expired. Please log in again. ``` ## Customization Guide ### Change Hardcoded User In `widgets/target-auth.html`: ```javascript // Change this line name: 'Lauren Bailey' // To your preferred name name: 'John Doe' ``` In `server.js` (if you want to simulate different users): ```javascript const DEMO_USERS = { 'user1@example.com': { name: 'Alice Smith', role: 'admin' }, 'user2@example.com': { name: 'Bob Jones', role: 'user' } }; // In authenticate endpoint const user = DEMO_USERS[email] || { name: 'Guest User', role: 'guest' }; ``` ### Add Real Authentication Replace demo logic with actual authentication: ```javascript // Instead of always accepting credentials const isValid = await verifyCredentials(email, password); if (!isValid) { return { error: 'Invalid credentials' }; } // Verify 2FA code const isCodeValid = await verify2FACode(email, code); ``` ### Change Branding In `widgets/target-auth.html`: ```html <!-- Change logo --> <img src="your-logo-url.png" alt="Your Brand" /> <!-- Change colors --> <style> body.light { background: linear-gradient(135deg, #your-color1 0%, #your-color2 100%); } .sign-in-btn { background: #your-brand-color; } </style> ``` ## Testing Checklist - [ ] Session creation returns unique IDs - [ ] Login widget displays correctly - [ ] Any email/password works (demo mode) - [ ] Verification code auto-advances inputs - [ ] Any 6-digit code works - [ ] Success screen appears with correct name - [ ] ChatGPT receives authenticated state - [ ] `get-target-auth-status` returns correct data - [ ] Dark mode renders correctly - [ ] Light mode renders correctly - [ ] Session cleanup works (wait 10+ minutes) - [ ] Multiple sessions don't interfere ## Common Issues ### Widget shows "Loading..." indefinitely **Cause**: `sessionId` not passed to widget **Fix**: Ensure `authenticate-target` is called AFTER `create-target-session` ### "Session not found" error **Cause**: Session expired or never created **Fix**: Create a new session with `create-target-session` ### Widget appears twice **Cause**: ChatGPT calling `authenticate-target` multiple times **Fix**: This is expected behavior. The second call should show the success screen if already authenticated. ## Next Steps - Add real OAuth integration (Google, Microsoft) - Store sessions in Redis for persistence - Add password reset flow - Implement rate limiting - Add CAPTCHA for security - Support multiple user profiles --- **Related Examples**: - [Product Search](product-search.md) - Uses authentication session - [Checkout](checkout.md) - Requires authenticated user - [Architecture](../ARCHITECTURE.md) - System overview

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/skyrmionz/chatgpt-mcp-server-interactive-components'

If you have feedback or need assistance with the MCP directory API, please join our Discord server