Disable password login once a passkey is linked
- /token: reject password auth with a clear message if pocketid_sub is set on the account — passkey-linked users must sign in via PocketID - Link callback + auto-link-by-email: null out hashed_password when the passkey is attached so the old hash can't be used even if the check above were bypassed Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user