How to Handle CSRF Token Expiration and Refresh Authentication in notebooklm-py
NotebookLM-py automatically detects expired CSRF tokens and session IDs, then refreshes them by re-fetching the homepage and updating the HTTP client headers, with built-in retry logic for seamless authentication recovery.
When working with the unofficial notebooklm-py client, handling authentication state is critical for maintaining uninterrupted API access. The library manages two essential tokens—a CSRF token (SNlM0e) and a session ID (FdrFJe)—that expire after periods of inactivity. This guide explains how notebooklm-py handles CSRF token expiration and refresh authentication automatically, plus how to manually trigger refreshes when needed.
Understanding CSRF Token Expiration in notebooklm-py
The AuthTokens System (SNlM0e and FdrFJe)
NotebookLM's web interface requires two tokens for every RPC request: SNlM0e (the CSRF token) and FdrFJe (the session identifier). These are extracted from the HTML of the NotebookLM homepage and stored in an AuthTokens object within the client's core. According to the source code in src/notebooklm/client.py, these tokens are initially obtained during client initialization and are bound to the HTTP client's cookie jar.
When Tokens Expire
Tokens typically expire when a user's session times out due to inactivity or when Google invalidates the session server-side. When this happens, RPC requests return HTTP 401 or 403 errors, or raise an AuthError. The is_auth_error helper function in src/notebooklm/_core.py specifically checks for these conditions to distinguish authentication failures from other API errors.
Automatic Token Refresh Mechanism
The refresh_auth() Method
The primary method for handling token expiration is NotebookLMClient.refresh_auth() in src/notebooklm/client.py. This method explicitly reloads the NotebookLM homepage, extracts fresh SNlM0e and FdrFJe values using regex parsing, and updates the shared ClientCore authentication object. If the homepage HTML does not contain the expected tokens, the method raises a ValueError indicating that the underlying Google account session may have expired completely.
update_auth_headers() Integration
Once new tokens are obtained, refresh_auth() calls self._core.update_auth_headers() (defined in src/notebooklm/_core.py). This method injects the updated CSRF and session values into the httpx.AsyncClient instance used for subsequent RPC calls. Specifically, it reconstructs the Cookie header with the new SNlM0e value, ensuring that the next request presents valid authentication credentials.
Automatic Retry on Authentication Failure
All RPC calls in notebooklm-py route through ClientCore.rpc_call() in src/notebooklm/_core.py. This method implements automatic retry logic: when an HTTP 401/403 or AuthError is detected (via is_auth_error), and if a _refresh_callback is configured, the method invokes the callback (which points to NotebookLMClient.refresh_auth) and retries the original request exactly once. This seamless handling means that for most use cases, you do not need to manually manage token expiration.
Manual Token Refresh Methods
While automatic refresh handles most scenarios, you may want to manually refresh tokens before a critical operation or after detecting a long idle period.
import asyncio
from notebooklm.client import NotebookLMClient
async def main():
client = await NotebookLMClient.from_storage()
await client.__aenter__() # Open the HTTP client manually
try:
# Force a token refresh (e.g., after a long idle period)
refreshed = await client.refresh_auth()
print("New CSRF:", refreshed.csrf_token)
# Continue with normal API calls
notebooks = await client.notebooks.list()
print(notebooks)
finally:
await client.__aexit__(None, None, None) # Close the client
asyncio.run(main())
The refresh_auth() method returns the updated AuthTokens object, allowing you to inspect the new csrf_token and session_id values if needed.
Detecting Token Expiration in Custom Code
If you are making raw HTTP calls outside the high-level client, you can reuse the same authentication helpers to detect and handle expiration.
from notebooklm.auth import fetch_tokens, load_auth_from_storage
# Load existing cookies from Playwright storage state
cookies = load_auth_from_storage()
# Get fresh tokens (CSRF + session) directly from the homepage
csrf, session_id = await fetch_tokens(cookies)
# Build a request header for subsequent calls
headers = {"Cookie": f"SID={cookies['SID']}; SNlM0e={csrf}"}
The fetch_tokens function performs the same homepage request and regex parsing that refresh_auth uses internally, making it ideal for custom authentication flows.
Summary
- Automatic handling: The
NotebookLMClientautomatically detects CSRF token expiration viais_auth_errorand triggersrefresh_auth()to fetch new tokens from the NotebookLM homepage. - Core components: Token refresh relies on three coordinated pieces:
refresh_auth()insrc/notebooklm/client.py,update_auth_headers()insrc/notebooklm/_core.py, and automatic retry logic inrpc_call(). - Manual control: You can explicitly call
await client.refresh_auth()to preemptively refresh tokens before critical operations or after long idle periods. - Custom implementations: The
fetch_tokensandload_auth_from_storagehelpers insrc/notebooklm/auth.pyallow you to handle token expiration in custom HTTP clients.
Frequently Asked Questions
How does notebooklm-py detect when a CSRF token has expired?
The library uses the is_auth_error helper function in src/notebooklm/_core.py to check for HTTP 401/403 status codes or AuthError exceptions. When rpc_call detects these conditions, it triggers the automatic refresh callback before retrying the request.
Can I disable automatic token refresh in notebooklm-py?
While the library is designed to handle authentication seamlessly, you can effectively disable automatic refresh by not using the high-level NotebookLMClient and instead making raw HTTP calls with manually managed tokens using the fetch_tokens helper from src/notebooklm/auth.py.
What happens if the refresh_auth() method fails to extract new tokens?
If refresh_auth() in src/notebooklm/client.py cannot find the SNlM0e or FdrFJe tokens in the homepage HTML, it raises a ValueError. This typically indicates that the underlying Google account session has expired completely, requiring you to re-authenticate via Playwright and regenerate the storage state file.
How often should I manually call refresh_auth() in long-running applications?
For most use cases, you do not need to manually refresh tokens because the automatic retry mechanism handles expiration transparently. However, if your application experiences long idle periods (e.g., hours between requests) or performs critical operations that cannot tolerate even a single retry delay, calling await client.refresh_auth() proactively before those operations is recommended.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →