feat(auth): add logout command and --fresh flag for login#288
feat(auth): add logout command and --fresh flag for login#288MCR-GLOBAL wants to merge 1 commit intoteng-lin:mainfrom
Conversation
Users couldn't switch Google accounts because the cached browser profile at ~/.notebooklm/browser_profile/ retained session cookies from the previous account. - Add `notebooklm auth logout` command that clears both storage_state.json and the browser profile directory - Add `notebooklm login --fresh` flag that clears the cached browser profile before opening the login browser, allowing account switching Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthroughExtended the login CLI command with a Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request introduces a --fresh flag to the login command and adds a new logout command to manage authentication state by clearing cached browser profiles and saved auth files. The review feedback suggests also clearing the local notebook context in both scenarios to prevent stale state when switching accounts or logging out, and recommends adding error handling for file operations to handle locked files gracefully.
| if fresh: | ||
| import shutil | ||
|
|
||
| if browser_profile.exists(): | ||
| shutil.rmtree(browser_profile) | ||
| console.print("[yellow]Cleared cached browser profile.[/yellow]") | ||
| if storage_path.exists(): | ||
| storage_path.unlink() | ||
| console.print("[yellow]Cleared saved auth state.[/yellow]") |
There was a problem hiding this comment.
When performing a --fresh login, it is important to also clear the current notebook context. Since this flag is intended for switching accounts, any previously selected notebook ID in context.json will likely be invalid for the new account. Additionally, wrapping these file operations in a try-except block prevents the command from crashing if files are locked (e.g., by an active browser process), allowing for a more graceful warning.
| if fresh: | |
| import shutil | |
| if browser_profile.exists(): | |
| shutil.rmtree(browser_profile) | |
| console.print("[yellow]Cleared cached browser profile.[/yellow]") | |
| if storage_path.exists(): | |
| storage_path.unlink() | |
| console.print("[yellow]Cleared saved auth state.[/yellow]") | |
| if fresh: | |
| import shutil | |
| try: | |
| if browser_profile.exists(): | |
| shutil.rmtree(browser_profile) | |
| console.print("[yellow]Cleared cached browser profile.[/yellow]") | |
| if storage_path.exists(): | |
| storage_path.unlink() | |
| console.print("[yellow]Cleared saved auth state.[/yellow]") | |
| clear_context() | |
| except OSError as e: | |
| console.print(f"[yellow]Warning: Could not fully clear profile: {e}[/yellow]") |
| cleared = False | ||
| if storage_path.exists(): | ||
| storage_path.unlink() | ||
| console.print("[green]Removed auth state.[/green]") | ||
| cleared = True | ||
| if browser_profile.exists(): | ||
| shutil.rmtree(browser_profile) | ||
| console.print("[green]Removed cached browser profile.[/green]") | ||
| cleared = True |
There was a problem hiding this comment.
The logout command should also clear the local notebook context (context.json) to prevent stale state issues after the user is unauthenticated. Furthermore, adding error handling for the file operations ensures the command doesn't terminate abruptly if the browser profile directory is locked by another process.
| cleared = False | |
| if storage_path.exists(): | |
| storage_path.unlink() | |
| console.print("[green]Removed auth state.[/green]") | |
| cleared = True | |
| if browser_profile.exists(): | |
| shutil.rmtree(browser_profile) | |
| console.print("[green]Removed cached browser profile.[/green]") | |
| cleared = True | |
| cleared = False | |
| try: | |
| if storage_path.exists(): | |
| storage_path.unlink() | |
| console.print("[green]Removed auth state.[/green]") | |
| cleared = True | |
| if browser_profile.exists(): | |
| shutil.rmtree(browser_profile) | |
| console.print("[green]Removed cached browser profile.[/green]") | |
| cleared = True | |
| if get_context_path().exists(): | |
| clear_context() | |
| cleared = True | |
| except OSError as e: | |
| console.print(f"[red]Error during logout:[/red] {e}") | |
| raise SystemExit(1) |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/notebooklm/cli/session.py`:
- Around line 409-418: The current fresh-login branch deletes the existing
storage_state.json before the new login is confirmed; keep clearing the
browser_profile to force account selection but do NOT unlink storage_path (the
current auth file) here. Instead, remove the storage_path.unlink() call from the
fresh block and move the deletion/write responsibility to the successful
login/Playwright startup path (the code that creates/writes storage_state.json)
so that storage_path is only replaced after Playwright/Chromium launches and
login succeeds. Identify the variables browser_profile, storage_path and the
fresh branch to make this change.
- Around line 970-997: The auth_logout command (function auth_logout) can
misleadingly report success when NOTEBOOKLM_AUTH_JSON is set because subsequent
commands will still use the env-provided auth; update auth_logout to detect
os.environ.get("NOTEBOOKLM_AUTH_JSON") (or equivalent env access) before
removing storage_state.json (via get_storage_path()) and browser profile (via
get_browser_profile_dir()) and if the env var is set, refuse to proceed (exit
the command) or print an explicit, prominent message telling the user to unset
NOTEBOOKLM_AUTH_JSON first (and how to do so) instead of reporting logout
success; ensure the branch that checks the env var runs before any filesystem
removal and that the console message clearly instructs to unset the variable.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 745363fe-9252-4410-b2ef-38fd7b80fc3f
📒 Files selected for processing (1)
src/notebooklm/cli/session.py
| # Clear cached browser profile to allow switching Google accounts | ||
| if fresh: | ||
| import shutil | ||
|
|
||
| if browser_profile.exists(): | ||
| shutil.rmtree(browser_profile) | ||
| console.print("[yellow]Cleared cached browser profile.[/yellow]") | ||
| if storage_path.exists(): | ||
| storage_path.unlink() | ||
| console.print("[yellow]Cleared saved auth state.[/yellow]") |
There was a problem hiding this comment.
Don't delete the current auth file before a replacement exists.
Line 416 logs the user out before the fresh login flow has even verified that Playwright/Chromium can start. If import, install, or browser launch fails, notebooklm login --fresh leaves a previously working session unusable. Clearing the cached browser profile is enough to force account selection; let the new storage_state.json be written only after login succeeds.
Suggested fix
# Clear cached browser profile to allow switching Google accounts
if fresh:
import shutil
if browser_profile.exists():
shutil.rmtree(browser_profile)
console.print("[yellow]Cleared cached browser profile.[/yellow]")
- if storage_path.exists():
- storage_path.unlink()
- console.print("[yellow]Cleared saved auth state.[/yellow]")🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/notebooklm/cli/session.py` around lines 409 - 418, The current
fresh-login branch deletes the existing storage_state.json before the new login
is confirmed; keep clearing the browser_profile to force account selection but
do NOT unlink storage_path (the current auth file) here. Instead, remove the
storage_path.unlink() call from the fresh block and move the deletion/write
responsibility to the successful login/Playwright startup path (the code that
creates/writes storage_state.json) so that storage_path is only replaced after
Playwright/Chromium launches and login succeeds. Identify the variables
browser_profile, storage_path and the fresh branch to make this change.
| @auth_group.command("logout") | ||
| def auth_logout(): | ||
| """Log out by clearing saved auth state and browser profile. | ||
|
|
||
| Removes the storage_state.json and the cached browser profile | ||
| for the current profile. After logout, run 'notebooklm login' | ||
| to authenticate with a different account. | ||
| """ | ||
| import shutil | ||
|
|
||
| storage_path = get_storage_path() | ||
| browser_profile = get_browser_profile_dir() | ||
|
|
||
| cleared = False | ||
| if storage_path.exists(): | ||
| storage_path.unlink() | ||
| console.print("[green]Removed auth state.[/green]") | ||
| cleared = True | ||
| if browser_profile.exists(): | ||
| shutil.rmtree(browser_profile) | ||
| console.print("[green]Removed cached browser profile.[/green]") | ||
| cleared = True | ||
|
|
||
| if cleared: | ||
| console.print("\n[green]Logged out successfully.[/green]") | ||
| console.print("[dim]Run 'notebooklm login' to sign in again.[/dim]") | ||
| else: | ||
| console.print("[yellow]No auth state found — already logged out.[/yellow]") |
There was a problem hiding this comment.
auth logout is misleading when NOTEBOOKLM_AUTH_JSON is set.
This file already treats NOTEBOOKLM_AUTH_JSON as an active auth source, so this command can report success while later commands still authenticate via the environment variable. Refuse the command or emit an explicit instruction to unset the env var first.
Suggested fix
`@auth_group.command`("logout")
def auth_logout():
"""Log out by clearing saved auth state and browser profile.
@@
to authenticate with a different account.
"""
import shutil
+
+ if os.environ.get("NOTEBOOKLM_AUTH_JSON"):
+ console.print(
+ "[red]Error: Cannot log out while NOTEBOOKLM_AUTH_JSON is set.[/red]\n"
+ "Unset NOTEBOOKLM_AUTH_JSON to remove inline authentication."
+ )
+ raise SystemExit(1)
storage_path = get_storage_path()
browser_profile = get_browser_profile_dir()🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/notebooklm/cli/session.py` around lines 970 - 997, The auth_logout
command (function auth_logout) can misleadingly report success when
NOTEBOOKLM_AUTH_JSON is set because subsequent commands will still use the
env-provided auth; update auth_logout to detect
os.environ.get("NOTEBOOKLM_AUTH_JSON") (or equivalent env access) before
removing storage_state.json (via get_storage_path()) and browser profile (via
get_browser_profile_dir()) and if the env var is set, refuse to proceed (exit
the command) or print an explicit, prominent message telling the user to unset
NOTEBOOKLM_AUTH_JSON first (and how to do so) instead of reporting logout
success; ensure the branch that checks the env var runs before any filesystem
removal and that the console message clearly instructs to unset the variable.
Summary
notebooklm auth logoutcommand — clears bothstorage_state.jsonand browser profilenotebooklm login --freshflag — clears cached browser profile before login to allow account switchingUsage
Test plan
notebooklm login --helpshows--freshflagnotebooklm auth logout --helpshows correct usagenotebooklm login --freshallows switching to a different Google account🤖 Generated with Claude Code
Summary by CodeRabbit
--freshflag to login command to reset cached browser profile and authentication state before logging inauth logoutcommand to clear all authentication and cached browser data