diff --git a/auth/fastmcp_google_auth.py b/auth/fastmcp_google_auth.py
index e52b1a6..b43bd08 100644
--- a/auth/fastmcp_google_auth.py
+++ b/auth/fastmcp_google_auth.py
@@ -84,11 +84,23 @@ class GoogleWorkspaceAuthProvider(AuthProvider):
                     store = get_oauth21_session_store()
                     session_id = f"google_{access_token.claims.get('sub', 'unknown')}"
                     
+                    # Try to get FastMCP session ID for binding
+                    mcp_session_id = None
+                    try:
+                        from fastmcp.server.dependencies import get_context
+                        ctx = get_context()
+                        if ctx and hasattr(ctx, 'session_id'):
+                            mcp_session_id = ctx.session_id
+                            logger.debug(f"Binding MCP session {mcp_session_id} to user {user_email}")
+                    except Exception:
+                        pass
+                    
                     store.store_session(
                         user_email=user_email,
                         access_token=token,
                         scopes=access_token.scopes or [],
-                        session_id=session_id
+                        session_id=session_id,
+                        mcp_session_id=mcp_session_id
                     )
                 
                 logger.debug(f"Successfully verified Google token for user: {user_email}")
diff --git a/auth/oauth21_session_store.py b/auth/oauth21_session_store.py
index 6e05886..3950570 100644
--- a/auth/oauth21_session_store.py
+++ b/auth/oauth21_session_store.py
@@ -119,9 +119,21 @@ def extract_session_from_headers(headers: Dict[str, str]) -> Optional[str]:
     # Try Authorization header for Bearer token
     auth_header = headers.get("authorization") or headers.get("Authorization")
     if auth_header and auth_header.lower().startswith("bearer "):
-        # For now, we can't extract session from bearer token without the full context
-        # This would need to be handled by the OAuth 2.1 middleware
-        pass
+        # Extract bearer token and try to find associated session
+        token = auth_header[7:]  # Remove "Bearer " prefix
+        if token:
+            # Look for a session that has this access token
+            # This requires scanning sessions, but bearer tokens should be unique
+            store = get_oauth21_session_store()
+            for user_email, session_info in store._sessions.items():
+                if session_info.get("access_token") == token:
+                    return session_info.get("session_id") or f"bearer_{user_email}"
+        
+        # If no session found, create a temporary session ID from token hash
+        # This allows header-based authentication to work with session context
+        import hashlib
+        token_hash = hashlib.sha256(token.encode()).hexdigest()[:8]
+        return f"bearer_token_{token_hash}"
 
     return None
 
@@ -137,11 +149,15 @@ class OAuth21SessionStore:
     This store maintains a mapping of user emails to their OAuth 2.1
     authenticated credentials, allowing Google services to access them.
     It also maintains a mapping from FastMCP session IDs to user emails.
+    
+    Security: Sessions are bound to specific users and can only access
+    their own credentials.
     """
     
     def __init__(self):
         self._sessions: Dict[str, Dict[str, Any]] = {}
         self._mcp_session_mapping: Dict[str, str] = {}  # Maps FastMCP session ID -> user email
+        self._session_auth_binding: Dict[str, str] = {}  # Maps session ID -> authenticated user email (immutable)
         self._lock = RLock()
     
     def store_session(
@@ -189,10 +205,23 @@ class OAuth21SessionStore:
             
             # Store MCP session mapping if provided
             if mcp_session_id:
+                # Create immutable session binding (first binding wins, cannot be changed)
+                if mcp_session_id not in self._session_auth_binding:
+                    self._session_auth_binding[mcp_session_id] = user_email
+                    logger.info(f"Created immutable session binding: {mcp_session_id} -> {user_email}")
+                elif self._session_auth_binding[mcp_session_id] != user_email:
+                    # Security: Attempt to bind session to different user
+                    logger.error(f"SECURITY: Attempt to rebind session {mcp_session_id} from {self._session_auth_binding[mcp_session_id]} to {user_email}")
+                    raise ValueError(f"Session {mcp_session_id} is already bound to a different user")
+                
                 self._mcp_session_mapping[mcp_session_id] = user_email
                 logger.info(f"Stored OAuth 2.1 session for {user_email} (session_id: {session_id}, mcp_session_id: {mcp_session_id})")
             else:
                 logger.info(f"Stored OAuth 2.1 session for {user_email} (session_id: {session_id})")
+            
+            # Also create binding for the OAuth session ID
+            if session_id and session_id not in self._session_auth_binding:
+                self._session_auth_binding[session_id] = user_email
     
     def get_credentials(self, user_email: str) -> Optional[Credentials]:
         """
@@ -249,6 +278,79 @@ class OAuth21SessionStore:
             logger.debug(f"Found user {user_email} for MCP session {mcp_session_id}")
             return self.get_credentials(user_email)
     
+    def get_credentials_with_validation(
+        self, 
+        requested_user_email: str, 
+        session_id: Optional[str] = None,
+        auth_token_email: Optional[str] = None,
+        allow_recent_auth: bool = False
+    ) -> Optional[Credentials]:
+        """
+        Get Google credentials with session validation.
+        
+        This method ensures that a session can only access credentials for its
+        authenticated user, preventing cross-account access.
+        
+        Args:
+            requested_user_email: The email of the user whose credentials are requested
+            session_id: The current session ID (MCP or OAuth session)
+            auth_token_email: Email from the verified auth token (if available)
+            
+        Returns:
+            Google Credentials object if validation passes, None otherwise
+        """
+        with self._lock:
+            # Priority 1: Check auth token email (most secure, from verified JWT)
+            if auth_token_email:
+                if auth_token_email != requested_user_email:
+                    logger.error(
+                        f"SECURITY VIOLATION: Token for {auth_token_email} attempted to access "
+                        f"credentials for {requested_user_email}"
+                    )
+                    return None
+                # Token email matches, allow access
+                return self.get_credentials(requested_user_email)
+            
+            # Priority 2: Check session binding
+            if session_id:
+                bound_user = self._session_auth_binding.get(session_id)
+                if bound_user:
+                    if bound_user != requested_user_email:
+                        logger.error(
+                            f"SECURITY VIOLATION: Session {session_id} (bound to {bound_user}) "
+                            f"attempted to access credentials for {requested_user_email}"
+                        )
+                        return None
+                    # Session binding matches, allow access
+                    return self.get_credentials(requested_user_email)
+                
+                # Check if this is an MCP session
+                mcp_user = self._mcp_session_mapping.get(session_id)
+                if mcp_user:
+                    if mcp_user != requested_user_email:
+                        logger.error(
+                            f"SECURITY VIOLATION: MCP session {session_id} (user {mcp_user}) "
+                            f"attempted to access credentials for {requested_user_email}"
+                        )
+                        return None
+                    # MCP session matches, allow access
+                    return self.get_credentials(requested_user_email)
+            
+            # Special case: Allow access if user has recently authenticated (for clients that don't send tokens)
+            # This is a temporary workaround for MCP clients that complete OAuth but don't send bearer tokens
+            if allow_recent_auth and requested_user_email in self._sessions:
+                logger.info(
+                    f"Allowing credential access for {requested_user_email} based on recent authentication "
+                    f"(client not sending bearer token)"
+                )
+                return self.get_credentials(requested_user_email)
+            
+            # No session or token info available - deny access for security
+            logger.warning(
+                f"Credential access denied for {requested_user_email}: No valid session or token"
+            )
+            return None
+    
     def get_user_by_mcp_session(self, mcp_session_id: str) -> Optional[str]:
         """
         Get user email by FastMCP session ID.
@@ -266,9 +368,10 @@ class OAuth21SessionStore:
         """Remove session for a user."""
         with self._lock:
             if user_email in self._sessions:
-                # Get MCP session ID if exists to clean up mapping
+                # Get session IDs to clean up mappings
                 session_info = self._sessions.get(user_email, {})
                 mcp_session_id = session_info.get("mcp_session_id")
+                session_id = session_info.get("session_id")
                 
                 # Remove from sessions
                 del self._sessions[user_email]
@@ -276,8 +379,16 @@ class OAuth21SessionStore:
                 # Remove from MCP mapping if exists
                 if mcp_session_id and mcp_session_id in self._mcp_session_mapping:
                     del self._mcp_session_mapping[mcp_session_id]
+                    # Also remove from auth binding
+                    if mcp_session_id in self._session_auth_binding:
+                        del self._session_auth_binding[mcp_session_id]
                     logger.info(f"Removed OAuth 2.1 session for {user_email} and MCP mapping for {mcp_session_id}")
-                else:
+                
+                # Remove OAuth session binding if exists
+                if session_id and session_id in self._session_auth_binding:
+                    del self._session_auth_binding[session_id]
+                
+                if not mcp_session_id:
                     logger.info(f"Removed OAuth 2.1 session for {user_email}")
     
     def has_session(self, user_email: str) -> bool:
diff --git a/auth/service_decorator.py b/auth/service_decorator.py
index b2b2736..f9fac2c 100644
--- a/auth/service_decorator.py
+++ b/auth/service_decorator.py
@@ -23,25 +23,103 @@ from auth.oauth21_session_store import get_session_context
 # OAuth 2.1 integration is now handled by FastMCP auth
 OAUTH21_INTEGRATION_AVAILABLE = True
 
+
+async def _extract_and_verify_bearer_token() -> tuple[Optional[str], Optional[str]]:
+    """
+    Extract and verify bearer token from HTTP headers.
+    
+    Returns:
+        Tuple of (user_email, verified_token) if valid, (None, None) if invalid or not found
+    """
+    try:
+        from fastmcp.server.dependencies import get_http_headers
+        headers = get_http_headers()
+        
+        if not headers:
+            logger.debug("No HTTP headers available for bearer token extraction")
+            return None, None
+            
+        # Look for Authorization header
+        auth_header = headers.get("authorization") or headers.get("Authorization")
+        if not auth_header:
+            logger.debug("No Authorization header found in request")
+            return None, None
+            
+        if not auth_header.lower().startswith("bearer "):
+            logger.debug(f"Authorization header present but not Bearer token: {auth_header[:20]}...")
+            return None, None
+            
+        # Extract token
+        token = auth_header[7:]  # Remove "Bearer " prefix
+        if not token:
+            logger.debug("Empty bearer token found")
+            return None, None
+        
+        logger.debug(f"Found bearer token in Authorization header: {token[:20]}...")
+        
+        # Verify token using GoogleWorkspaceAuthProvider
+        try:
+            from core.server import get_auth_provider
+            auth_provider = get_auth_provider()
+            if not auth_provider:
+                logger.debug("No auth provider available for token verification")
+                return None, None
+                
+            # Verify the token
+            access_token = await auth_provider.verify_token(token)
+            if not access_token:
+                logger.debug("Bearer token verification failed")
+                return None, None
+                
+            # Extract user email from verified token
+            user_email = access_token.claims.get("email")
+            if not user_email:
+                logger.debug("No email claim found in verified token")
+                return None, None
+                
+            logger.info(f"Successfully verified bearer token for user: {user_email}")
+            return user_email, token
+            
+        except Exception as e:
+            logger.error(f"Error verifying bearer token: {e}")
+            return None, None
+            
+    except Exception as e:
+        logger.debug(f"Error extracting bearer token from headers: {e}")
+        return None, None
+
 async def get_authenticated_google_service_oauth21(
     service_name: str,
     version: str,
     tool_name: str,
     user_google_email: str,
     required_scopes: List[str],
+    session_id: Optional[str] = None,
+    auth_token_email: Optional[str] = None,
+    allow_recent_auth: bool = False,
 ) -> tuple[Any, str]:
     """
-    OAuth 2.1 authentication using the session store.
+    OAuth 2.1 authentication using the session store with security validation.
     """
     from auth.oauth21_session_store import get_oauth21_session_store
     from googleapiclient.discovery import build
     
     store = get_oauth21_session_store()
-    credentials = store.get_credentials(user_google_email)
+    
+    # Use the new validation method to ensure session can only access its own credentials
+    credentials = store.get_credentials_with_validation(
+        requested_user_email=user_google_email,
+        session_id=session_id,
+        auth_token_email=auth_token_email,
+        allow_recent_auth=allow_recent_auth
+    )
     
     if not credentials:
         from auth.google_auth import GoogleAuthenticationError
-        raise GoogleAuthenticationError(f"No OAuth 2.1 credentials found for {user_google_email}")
+        raise GoogleAuthenticationError(
+            f"Access denied: Cannot retrieve credentials for {user_google_email}. "
+            f"You can only access credentials for your authenticated account."
+        )
     
     # Check scopes
     if not all(scope in credentials.scopes for scope in required_scopes):
@@ -294,8 +372,9 @@ def require_google_service(
                     
                     # Check if we have OAuth 2.1 credentials for this user
                     session_ctx = None
+                    auth_token_email = None
                     
-                    # Try to get FastMCP session ID (for future use)
+                    # Try to get FastMCP session ID and auth info
                     mcp_session_id = None
                     session_ctx = None
                     try:
@@ -309,12 +388,18 @@ def require_google_service(
                             from core.context import set_fastmcp_session_id
                             set_fastmcp_session_id(mcp_session_id)
                             
+                            # Extract authenticated email from auth context if available
+                            if hasattr(fastmcp_ctx, 'auth') and fastmcp_ctx.auth:
+                                if hasattr(fastmcp_ctx.auth, 'claims') and fastmcp_ctx.auth.claims:
+                                    auth_token_email = fastmcp_ctx.auth.claims.get('email')
+                                    logger.debug(f"[{tool_name}] Got authenticated email from token: {auth_token_email}")
+                            
                             # Create session context using FastMCP session ID
                             from auth.oauth21_session_store import SessionContext
                             session_ctx = SessionContext(
                                 session_id=mcp_session_id,
-                                user_id=user_google_email,
-                                metadata={"fastmcp_session_id": mcp_session_id, "user_email": user_google_email}
+                                user_id=auth_token_email or user_google_email,
+                                metadata={"fastmcp_session_id": mcp_session_id, "user_email": user_google_email, "auth_email": auth_token_email}
                             )
                     except Exception as e:
                         logger.debug(f"[{tool_name}] Could not get FastMCP context: {e}")
@@ -323,40 +408,177 @@ def require_google_service(
                     if not session_ctx and OAUTH21_INTEGRATION_AVAILABLE:
                         session_ctx = get_session_context()
                     
-                    # Also check if user has credentials in OAuth 2.1 store
-                    has_oauth21_creds = False
+                    # Check if the CURRENT REQUEST is authenticated
+                    is_authenticated_request = False
+                    authenticated_user = None
+                    bearer_token = None
+                    
                     if OAUTH21_INTEGRATION_AVAILABLE:
+                        # Check if we have an authenticated FastMCP context
                         try:
-                            from auth.oauth21_session_store import get_oauth21_session_store
-                            store = get_oauth21_session_store()
-                            has_oauth21_creds = store.has_session(user_google_email)
+                            from fastmcp.server.dependencies import get_context
+                            ctx = get_context()
+                            if ctx and hasattr(ctx, 'auth') and ctx.auth:
+                                # We have authentication info from FastMCP
+                                is_authenticated_request = True
+                                if hasattr(ctx.auth, 'claims'):
+                                    authenticated_user = ctx.auth.claims.get('email')
+                                logger.debug(f"[{tool_name}] Authenticated via FastMCP context: {authenticated_user}")
                         except Exception:
                             pass
+                        
+                        # If FastMCP context didn't provide authentication, check HTTP headers directly
+                        if not is_authenticated_request:
+                            logger.debug(f"[{tool_name}] FastMCP context has no auth, checking HTTP headers for bearer token")
+                            header_user, header_token = await _extract_and_verify_bearer_token()
+                            if header_user and header_token:
+                                is_authenticated_request = True
+                                authenticated_user = header_user
+                                bearer_token = header_token
+                                logger.info(f"[{tool_name}] Authenticated via HTTP bearer token: {authenticated_user}")
+                                
+                                # Create session binding for this bearer token authenticated request
+                                try:
+                                    from auth.oauth21_session_store import get_oauth21_session_store
+                                    store = get_oauth21_session_store()
+                                    # Create a session for this bearer token authentication
+                                    session_id = f"bearer_{authenticated_user}_{header_token[:8]}"
+                                    store.store_session(
+                                        user_email=authenticated_user,
+                                        access_token=header_token,
+                                        session_id=session_id,
+                                        mcp_session_id=mcp_session_id
+                                    )
+                                    logger.debug(f"[{tool_name}] Created session binding for bearer token auth: {session_id}")
+                                except Exception as e:
+                                    logger.warning(f"[{tool_name}] Could not create session binding for bearer token: {e}")
+                            else:
+                                logger.debug(f"[{tool_name}] No valid bearer token found in HTTP headers")
+                        
+                        # Fallback: Check other authentication indicators
+                        if not is_authenticated_request:
+                            # Check if MCP session is bound to a user
+                            mcp_user = None
+                            if mcp_session_id:
+                                try:
+                                    from auth.oauth21_session_store import get_oauth21_session_store
+                                    store = get_oauth21_session_store()
+                                    mcp_user = store.get_user_by_mcp_session(mcp_session_id)
+                                except Exception:
+                                    pass
+                            
+                            # TEMPORARY: Check if user has recently authenticated (for clients that don't send bearer tokens)
+                            # This still enforces that users can only access their own credentials
+                            has_recent_auth = False
+                            try:
+                                from auth.oauth21_session_store import get_oauth21_session_store
+                                store = get_oauth21_session_store()
+                                has_recent_auth = store.has_session(user_google_email)
+                                if has_recent_auth:
+                                    logger.info(f"[{tool_name}] User {user_google_email} has recent auth session (client not sending bearer token)")
+                            except Exception:
+                                pass
+                            
+                            is_authenticated_request = (
+                                auth_token_email is not None or 
+                                (session_ctx is not None and session_ctx.user_id) or
+                                mcp_user is not None or
+                                has_recent_auth  # Allow if user has authenticated (still validates in OAuth21SessionStore)
+                            )
                     
                     session_id_for_log = mcp_session_id if mcp_session_id else (session_ctx.session_id if session_ctx else 'None')
-                    logger.info(f"[{tool_name}] OAuth 2.1 available: {OAUTH21_INTEGRATION_AVAILABLE}, FastMCP Session ID: {mcp_session_id}, Session context: {session_ctx}, Session ID: {session_id_for_log}, Has OAuth21 creds: {has_oauth21_creds}")
+                    auth_method = "none"
+                    if authenticated_user:
+                        if bearer_token:
+                            auth_method = "bearer_token"
+                        elif auth_token_email:
+                            auth_method = "fastmcp_context"
+                        else:
+                            auth_method = "session"
                     
-                    if OAUTH21_INTEGRATION_AVAILABLE and (session_ctx or has_oauth21_creds):
-                        logger.info(f"[{tool_name}] Using OAuth 2.1 authentication")
+                    logger.info(f"[{tool_name}] Authentication Status:"
+                              f" Method={auth_method},"
+                              f" OAuth21={OAUTH21_INTEGRATION_AVAILABLE},"
+                              f" Authenticated={is_authenticated_request},"
+                              f" User={authenticated_user or 'none'},"
+                              f" SessionID={session_id_for_log},"
+                              f" MCPSessionID={mcp_session_id or 'none'}")
+                    
+                    # CRITICAL SECURITY: Check if OAuth 2.1 is enabled AND we're in HTTP mode
+                    from core.config import get_transport_mode
+                    transport_mode = get_transport_mode()
+                    
+                    # Check if OAuth 2.1 provider is configured (not just transport mode)
+                    oauth21_enabled = False
+                    try:
+                        from core.server import get_auth_provider
+                        auth_provider = get_auth_provider()
+                        oauth21_enabled = auth_provider is not None
+                    except Exception:
+                        pass
+                    
+                    if transport_mode == "streamable-http" and oauth21_enabled:
+                        # OAuth 2.1 is enabled - REQUIRE authentication, no fallback to files
+                        if not is_authenticated_request:
+                            logger.error(f"[{tool_name}] SECURITY: Unauthenticated request denied in OAuth 2.1 mode")
+                            raise Exception(
+                                "Authentication required. This server is configured with OAuth 2.1 authentication. "
+                                "Please authenticate first using the OAuth flow before accessing resources."
+                            )
+                        
+                        # Additional security: Verify the authenticated user matches the requested user
+                        # Only enforce this if we have a verified authenticated user from a token
+                        if authenticated_user and authenticated_user != user_google_email:
+                            logger.warning(
+                                f"[{tool_name}] User mismatch - token authenticated as {authenticated_user} "
+                                f"but requesting resources for {user_google_email}"
+                            )
+                            # The OAuth21SessionStore will handle the actual validation
+                        
+                        # Must use OAuth 2.1 authentication
+                        logger.info(f"[{tool_name}] Using OAuth 2.1 authentication (required for OAuth 2.1 mode)")
+                        
+                        # Check if we're allowing recent auth (for clients that don't send bearer tokens)
+                        allow_recent = not authenticated_user and not auth_token_email and not mcp_session_id
+                        
                         service, actual_user_email = await get_authenticated_google_service_oauth21(
                             service_name=service_name,
                             version=service_version,
                             tool_name=tool_name,
                             user_google_email=user_google_email,
                             required_scopes=resolved_scopes,
+                            session_id=mcp_session_id or (session_ctx.session_id if session_ctx else None),
+                            auth_token_email=auth_token_email or authenticated_user,  # Pass authenticated user
+                            allow_recent_auth=allow_recent,  # Allow recent auth for clients that don't send tokens
                         )
-                    else:
-                        # Fall back to legacy authentication
-                        session_id_for_legacy = mcp_session_id if mcp_session_id else (session_ctx.session_id if session_ctx else None)
-                        logger.info(f"[{tool_name}] Calling get_authenticated_google_service with session_id_for_legacy: {session_id_for_legacy}")
-                        service, actual_user_email = await get_authenticated_google_service(
+                    elif OAUTH21_INTEGRATION_AVAILABLE and is_authenticated_request:
+                        # In other modes, use OAuth 2.1 if available
+                        logger.info(f"[{tool_name}] Using OAuth 2.1 authentication")
+                        service, actual_user_email = await get_authenticated_google_service_oauth21(
                             service_name=service_name,
                             version=service_version,
                             tool_name=tool_name,
                             user_google_email=user_google_email,
                             required_scopes=resolved_scopes,
-                            session_id=session_id_for_legacy,
+                            session_id=mcp_session_id or (session_ctx.session_id if session_ctx else None),
+                            auth_token_email=auth_token_email,
                         )
+                    else:
+                        # Fall back to legacy authentication ONLY in stdio mode
+                        if transport_mode == "stdio":
+                            session_id_for_legacy = mcp_session_id if mcp_session_id else (session_ctx.session_id if session_ctx else None)
+                            logger.info(f"[{tool_name}] Using legacy authentication (stdio mode)")
+                            service, actual_user_email = await get_authenticated_google_service(
+                                service_name=service_name,
+                                version=service_version,
+                                tool_name=tool_name,
+                                user_google_email=user_google_email,
+                                required_scopes=resolved_scopes,
+                                session_id=session_id_for_legacy,
+                            )
+                        else:
+                            logger.error(f"[{tool_name}] No authentication available in {transport_mode} mode")
+                            raise Exception(f"Authentication not available in {transport_mode} mode")
                     
                     if cache_enabled:
                         cache_key = _get_cache_key(user_google_email, service_name, service_version, resolved_scopes)
@@ -436,9 +658,29 @@ def require_multiple_services(service_configs: List[Dict[str, Any]]):
                 try:
                     tool_name = func.__name__
                     
-                    # Try OAuth 2.1 integration first if available
-                    if OAUTH21_INTEGRATION_AVAILABLE and get_session_context():
-                        logger.debug(f"Attempting OAuth 2.1 authentication for {tool_name} ({service_type})")
+                    # Check if OAuth 2.1 is enabled AND we're in HTTP mode
+                    from core.config import get_transport_mode
+                    transport_mode = get_transport_mode()
+                    
+                    # Check if OAuth 2.1 provider is configured
+                    oauth21_enabled = False
+                    try:
+                        from core.server import get_auth_provider
+                        auth_provider = get_auth_provider()
+                        oauth21_enabled = auth_provider is not None
+                    except Exception:
+                        pass
+                    
+                    # In OAuth 2.1 mode, require authentication
+                    if transport_mode == "streamable-http" and oauth21_enabled:
+                        if not (OAUTH21_INTEGRATION_AVAILABLE and get_session_context()):
+                            logger.error(f"[{tool_name}] SECURITY: Unauthenticated request denied in OAuth 2.1 mode")
+                            raise Exception(
+                                "Authentication required. This server is configured with OAuth 2.1 authentication. "
+                                "Please authenticate first using the OAuth flow before accessing resources."
+                            )
+                        
+                        logger.debug(f"OAuth 2.1 authentication for {tool_name} ({service_type})")
                         service, _ = await get_authenticated_google_service_oauth21(
                             service_name=service_name,
                             version=service_version,
@@ -446,15 +688,28 @@ def require_multiple_services(service_configs: List[Dict[str, Any]]):
                             user_google_email=user_google_email,
                             required_scopes=resolved_scopes,
                         )
-                    else:
-                        # Fall back to legacy authentication
-                        service, _ = await get_authenticated_google_service(
+                    elif OAUTH21_INTEGRATION_AVAILABLE and get_session_context():
+                        logger.debug(f"Attempting OAuth 2.1 authentication for {tool_name} ({service_type})")
+                        service, _ = await get_authenticated_google_service_oauth21(
                             service_name=service_name,
                             version=service_version,
                             tool_name=tool_name,
                             user_google_email=user_google_email,
                             required_scopes=resolved_scopes,
                         )
+                    else:
+                        # Fall back to legacy authentication ONLY in stdio mode
+                        if transport_mode == "stdio":
+                            service, _ = await get_authenticated_google_service(
+                                service_name=service_name,
+                                version=service_version,
+                                tool_name=tool_name,
+                                user_google_email=user_google_email,
+                                required_scopes=resolved_scopes,
+                            )
+                        else:
+                            logger.error(f"[{tool_name}] No authentication available in {transport_mode} mode")
+                            raise Exception(f"Authentication not available in {transport_mode} mode")
 
                     # Inject service with specified parameter name
                     kwargs[param_name] = service
diff --git a/core/server.py b/core/server.py
index 7bb5a30..d0b60fb 100644
--- a/core/server.py
+++ b/core/server.py
@@ -241,6 +241,16 @@ async def oauth2_callback(request: Request) -> HTMLResponse:
         # Store Google credentials in OAuth 2.1 session store
         try:
             store = get_oauth21_session_store()
+            
+            # Try to get MCP session ID from request for binding
+            mcp_session_id = None
+            try:
+                if hasattr(request, 'state') and hasattr(request.state, 'session_id'):
+                    mcp_session_id = request.state.session_id
+                    logger.info(f"OAuth callback: Found MCP session ID for binding: {mcp_session_id}")
+            except Exception as e:
+                logger.debug(f"OAuth callback: Could not get MCP session ID: {e}")
+            
             store.store_session(
                 user_email=verified_user_id,
                 access_token=credentials.token,
@@ -251,8 +261,9 @@ async def oauth2_callback(request: Request) -> HTMLResponse:
                 scopes=credentials.scopes,
                 expiry=credentials.expiry,
                 session_id=f"google-{state}",  # Use state as a pseudo session ID
+                mcp_session_id=mcp_session_id,  # Bind to MCP session if available
             )
-            logger.info(f"Stored Google credentials in OAuth 2.1 session store for {verified_user_id}")
+            logger.info(f"Stored Google credentials in OAuth 2.1 session store for {verified_user_id} (mcp: {mcp_session_id})")
         except Exception as e:
             logger.error(f"Failed to store Google credentials in OAuth 2.1 store: {e}")
 
@@ -534,6 +545,29 @@ async def proxy_token_exchange(request: Request):
         # Get form data
         body = await request.body()
         content_type = request.headers.get("content-type", "application/x-www-form-urlencoded")
+        
+        # Parse form data to add missing client credentials
+        from urllib.parse import parse_qs, urlencode
+        
+        if content_type and "application/x-www-form-urlencoded" in content_type:
+            form_data = parse_qs(body.decode('utf-8'))
+            
+            # Check if client_id is missing (public client)
+            if 'client_id' not in form_data or not form_data['client_id'][0]:
+                client_id = os.getenv("GOOGLE_OAUTH_CLIENT_ID")
+                if client_id:
+                    form_data['client_id'] = [client_id]
+                    logger.debug(f"Added missing client_id to token request")
+            
+            # Check if client_secret is missing (public client using PKCE)
+            if 'client_secret' not in form_data:
+                client_secret = os.getenv("GOOGLE_OAUTH_CLIENT_SECRET")
+                if client_secret:
+                    form_data['client_secret'] = [client_secret]
+                    logger.debug(f"Added missing client_secret to token request")
+            
+            # Reconstruct body with added credentials
+            body = urlencode(form_data, doseq=True).encode('utf-8')
 
         # Forward request to Google
         async with aiohttp.ClientSession() as session:
@@ -570,37 +604,47 @@ async def proxy_token_exchange(request: Request):
                                         issuer="https://accounts.google.com"
                                     )
                                     user_email = id_token_claims.get("email")
+                                    
+                                    if user_email:
+                                        # Try to get FastMCP session ID from request context for binding
+                                        mcp_session_id = None
+                                        try:
+                                            # Check if this is a streamable HTTP request with session
+                                            if hasattr(request, 'state') and hasattr(request.state, 'session_id'):
+                                                mcp_session_id = request.state.session_id
+                                                logger.info(f"Found MCP session ID for binding: {mcp_session_id}")
+                                        except Exception as e:
+                                            logger.debug(f"Could not get MCP session ID: {e}")
+                                        
+                                        # Store the token session with MCP session binding
+                                        session_id = store_token_session(response_data, user_email, mcp_session_id)
+                                        logger.info(f"Stored OAuth session for {user_email} (session: {session_id}, mcp: {mcp_session_id})")
+
+                                        # Also create and store Google credentials
+                                        expiry = None
+                                        if "expires_in" in response_data:
+                                            # Google auth library expects timezone-naive datetime
+                                            expiry = datetime.utcnow() + timedelta(seconds=response_data["expires_in"])
+
+                                        credentials = Credentials(
+                                            token=response_data["access_token"],
+                                            refresh_token=response_data.get("refresh_token"),
+                                            token_uri="https://oauth2.googleapis.com/token",
+                                            client_id=os.getenv("GOOGLE_OAUTH_CLIENT_ID"),
+                                            client_secret=os.getenv("GOOGLE_OAUTH_CLIENT_SECRET"),
+                                            scopes=response_data.get("scope", "").split() if response_data.get("scope") else None,
+                                            expiry=expiry
+                                        )
+
+                                        # Save credentials to file for legacy auth
+                                        save_credentials_to_file(user_email, credentials)
+                                        logger.info(f"Saved Google credentials for {user_email}")
+                                except jwt.ExpiredSignatureError:
+                                    logger.error("ID token has expired - cannot extract user email")
+                                except jwt.InvalidTokenError as e:
+                                    logger.error(f"Invalid ID token - cannot extract user email: {e}")
                                 except Exception as e:
-                                    logger.error(f"Failed to verify ID token: {e}")
-                                    # Fallback to unverified decode for backwards compatibility (with warning)
-                                    logger.warning("Using unverified ID token decode as fallback - this should be fixed")
-                                    id_token_claims = jwt.decode(response_data["id_token"], options={"verify_signature": False})
-                                    user_email = id_token_claims.get("email")
-
-                                if user_email:
-                                    # Store the token session
-                                    session_id = store_token_session(response_data, user_email)
-                                    logger.info(f"Stored OAuth session for {user_email} (session: {session_id})")
-
-                                    # Also create and store Google credentials
-                                    expiry = None
-                                    if "expires_in" in response_data:
-                                        # Google auth library expects timezone-naive datetime
-                                        expiry = datetime.utcnow() + timedelta(seconds=response_data["expires_in"])
-
-                                    credentials = Credentials(
-                                        token=response_data["access_token"],
-                                        refresh_token=response_data.get("refresh_token"),
-                                        token_uri="https://oauth2.googleapis.com/token",
-                                        client_id=os.getenv("GOOGLE_OAUTH_CLIENT_ID"),
-                                        client_secret=os.getenv("GOOGLE_OAUTH_CLIENT_SECRET"),
-                                        scopes=response_data.get("scope", "").split() if response_data.get("scope") else None,
-                                        expiry=expiry
-                                    )
-
-                                    # Save credentials to file for legacy auth
-                                    save_credentials_to_file(user_email, credentials)
-                                    logger.info(f"Saved Google credentials for {user_email}")
+                                    logger.error(f"Failed to verify ID token - cannot extract user email: {e}")
 
                         except Exception as e:
                             logger.error(f"Failed to store OAuth session: {e}")
