diff --git a/backend/app/api/auth.py b/backend/app/api/auth.py index 923c8e5..13b070f 100644 --- a/backend/app/api/auth.py +++ b/backend/app/api/auth.py @@ -142,6 +142,11 @@ async def login( user = result.scalar_one_or_none() if not user or not user.hashed_password: raise HTTPException(status_code=400, detail="Invalid credentials") + if user.pocketid_sub is not None: + raise HTTPException( + status_code=400, + detail="Password login is disabled for this account — use your passkey to sign in.", + ) if not verify_password(form_data.password, user.hashed_password): raise HTTPException(status_code=400, detail="Invalid credentials") token = create_access_token({"sub": str(user.id)}) @@ -262,6 +267,7 @@ async def pocketid_callback(code: str, state: Optional[str] = None, db: AsyncSes if target is None: return RedirectResponse(url="/login?auth_error=link_failed") target.pocketid_sub = sub + target.hashed_password = None # disable password login once passkey is linked if not target.email and email: dup = await db.execute( select(User).where(User.email == email, User.id != target.id) @@ -293,6 +299,7 @@ async def pocketid_callback(code: str, state: Optional[str] = None, db: AsyncSes existing = result.scalar_one_or_none() if existing and existing.pocketid_sub is None: existing.pocketid_sub = sub + existing.hashed_password = None # disable password login once passkey is linked user = existing # 3) Otherwise provision a new account with a collision-safe username.