Skip to content

feat: 2fa backup codes#1

Open
ShashankFC wants to merge 1 commit into
enhance-two-factor-security-foundationfrom
improve-two-factor-authentication-features
Open

feat: 2fa backup codes#1
ShashankFC wants to merge 1 commit into
enhance-two-factor-security-foundationfrom
improve-two-factor-authentication-features

Conversation

@ShashankFC

Copy link
Copy Markdown

Test 3

Summary by CodeRabbit

Release Notes

  • New Features
    • Added backup codes as a secondary two-factor authentication method
    • Users can download, copy, and view backup codes when enabling 2FA
    • Added "Lost Access" recovery option allowing users to authenticate with backup codes if their authenticator app is unavailable
    • Users can disable 2FA using backup codes if they've lost access to their primary method

✏️ Tip: You can customize this high-level summary in your review settings.


Replicated from ai-code-review-evaluation/cal.com-coderabbit#3

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
@ShashankFC ShashankFC requested a review from Copilot January 30, 2026 10:18

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements backup codes as a secondary two-factor authentication method, providing users with a recovery option if they lose access to their authenticator app.

Changes:

  • Added backup code generation and storage in the database with encryption
  • Implemented backup code authentication flow for login and 2FA disabling
  • Added UI components for displaying, copying, and downloading backup codes

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
packages/prisma/schema.prisma Added backupCodes field to User model
packages/prisma/migrations/20230804153419_add_backup_codes/migration.sql Database migration to add backup codes column
packages/lib/test/builder.ts Updated test user builder with backupCodes field
packages/features/auth/lib/next-auth-options.ts Implemented backup code verification logic in login flow
packages/features/auth/lib/ErrorCode.ts Added error codes for backup code validation
apps/web/public/static/locales/en/common.json Added translations for backup code UI elements
apps/web/pages/auth/login.tsx Added "Lost Access" UI and backup code input handling
apps/web/pages/api/auth/two-factor/totp/setup.ts Generate backup codes during 2FA setup
apps/web/pages/api/auth/two-factor/totp/disable.ts Allow 2FA disabling with backup codes
apps/web/components/settings/TwoFactorAuthAPI.ts Updated API to accept backup codes
apps/web/components/settings/EnableTwoFactorModal.tsx Added backup code display step in setup flow
apps/web/components/settings/DisableTwoFactorModal.tsx Added backup code option for disabling 2FA
apps/web/components/auth/TwoFactor.tsx Added autoFocus prop for better UX
apps/web/components/auth/BackupCode.tsx New component for backup code input
packages/ui/components/form/inputs/Input.tsx Added tabIndex={-1} to password visibility toggle
apps/web/playwright/login.2fa.e2e.ts Added tests for backup code functionality

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Label, TextField } from "@calcom/ui";

export default function TwoFactor({ center = true }) {

Copilot AI Jan 30, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function name 'TwoFactor' does not match the component's purpose. It should be named 'BackupCode' to reflect that it handles backup code input.

Suggested change
export default function TwoFactor({ center = true }) {
export default function BackupCode({ center = true }) {

Copilot uses AI. Check for mistakes.

test.describe.configure({ mode: "parallel" });

// TODO: add more backup code tests, e.g. login + disabling 2fa with backup

Copilot AI Jan 30, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing test coverage for critical backup code scenarios including login with backup codes and disabling 2FA using backup codes.

Copilot uses AI. Check for mistakes.
const textBlob = new Blob([body.backupCodes.map(formatBackupCode).join("\n")], {
type: "text/plain",
});
if (backupCodesUrl) URL.revokeObjectURL(backupCodesUrl);

Copilot AI Jan 30, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Memory leak: The backup codes URL is created but never revoked when the component unmounts. Add cleanup in a useEffect to revoke the URL on unmount.

Copilot uses AI. Check for mistakes.
Comment on lines +147 to +154
// delete verified backup code and re-encrypt remaining
backupCodes[index] = null;
await prisma.user.update({
where: {
id: user.id,
},
data: {
backupCodes: symmetricEncrypt(JSON.stringify(backupCodes), process.env.CALENDSO_ENCRYPTION_KEY),

Copilot AI Jan 30, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting used backup codes to null creates sparse arrays. Consider filtering out used codes or using a different data structure to maintain a clean array of valid codes.

Suggested change
// delete verified backup code and re-encrypt remaining
backupCodes[index] = null;
await prisma.user.update({
where: {
id: user.id,
},
data: {
backupCodes: symmetricEncrypt(JSON.stringify(backupCodes), process.env.CALENDSO_ENCRYPTION_KEY),
// remove verified backup code and re-encrypt remaining valid codes
const updatedBackupCodes = backupCodes.filter((_, i) => i !== index);
await prisma.user.update({
where: {
id: user.id,
},
data: {
backupCodes: symmetricEncrypt(
JSON.stringify(updatedBackupCodes),
process.env.CALENDSO_ENCRYPTION_KEY
),

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants