Add authenticator app (TOTP) and YubiKey OTP two-factor sign-in - #173
Merged
Merged
Conversation
Accounts can now register authenticator apps and YubiKeys (Yubico OTP, checked on the server with the slot's AES key; no YubiCloud) from /account/2fa. Once one is registered, signing in needs a code from it or a single-use backup code, and emailed codes are no longer sent or accepted. Both sign-in paths share one check (checkSecondFactor): - com.atproto.server.createSession: codes arrive in authFactorToken, which the Bluesky app fills from its existing "emailed code" box after an AuthFactorTokenRequired response. - /account/signin, which the OAuth authorize flow uses. Codes can't be replayed (last TOTP step and YubiKey counter are claimed with conditional updates), and ten wrong codes in a row lock second-factor attempts for 15 minutes. Adding or removing a method needs the password plus a current code (an emailed code if the account only has email 2FA). getSession/createSession report emailAuthFactor for any second factor. Also fixes the signin page showing "Something went wrong!" for a wrong password, and returning raw JSON instead of a message for a wrong code.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
/account/2fapage.com.atproto.server.createSession(the Bluesky app sends the code from its existing "emailed code" box) and/account/signin, which the OAuth authorize flow uses.Changes
checkSecondFactor(server/two_factor.go) replaces the duplicated email-code logic increateSessionand the signin page. It tells codes apart by shape: 6 digits → authenticator, 32–48 modhex characters → YubiKey, otherwise → backup code.internal/totp(RFC 6238, SHA1 / 6 digits / 30 s, ±1 step) andinternal/yubiotp(modhex, AES-128 decryption, CRC and counter checks) packages. YubiKey OTPs are checked on the server using the slot's AES key; there is no YubiCloud dependency.two_factor_credentialsandtwo_factor_backup_codes, plusrepos.two_factor_failed_attempts/two_factor_locked_until(added by AutoMigrate).UPDATEs, so concurrent requests can't both use a code.createSessionreturnsRateLimitExceeded(429) while locked./account/2fapages: add an authenticator app (with QR code), add a YubiKey (instructions forykman otp yubiotp --serial-public-id --generate-private-id --generate-key 2), remove a method, and regenerate backup codes. Every change needs the password plus a current code: from an existing method, or an emailed code (via an "Email me a code" button) when the account only has email 2FA.getSession/createSessionnow reportemailAuthFactor: truefor any second factor.github.com/skip2/go-qrcode.Validation
CGO_ENABLED=1 go test -race ./...— all packages pass.go vet ./...andgofmt -l .— clean.yubico-c(test-vectors.txt,tests/selftest.c)./account/2faforms): the session cookie isSameSite=Laxand every change needs fresh secrets, which matches the rest of/account.Review notes