BA
Better Auth•2w ago
wvn

Backup Verify

# SERVER_ERROR: Error: padded hex string expected, got unpadded hex of length 191
at hexToBytes (../src/utils.ts:56:20)
POST /api/auth/two-factor/verify-backup-code 500 in 165ms
# SERVER_ERROR: Error: padded hex string expected, got unpadded hex of length 191
at hexToBytes (../src/utils.ts:56:20)
POST /api/auth/two-factor/verify-backup-code 500 in 165ms
const verifyBackupCode = async () => {
if (!backupCode.trim()) {
toast("Validation Error", {
description: "Please enter your backup code"
});
return;
}

setIsLoading(true);

console.log("Verifying backup code");

await authClient.twoFactor.verifyBackupCode({code: "j1rFA-Z3tNz"}, {
onSuccess(){
console.log("Success")
//redirect the user on success
},
onError(ctx){
alert(ctx.error.message)
}
})
};
const verifyBackupCode = async () => {
if (!backupCode.trim()) {
toast("Validation Error", {
description: "Please enter your backup code"
});
return;
}

setIsLoading(true);

console.log("Verifying backup code");

await authClient.twoFactor.verifyBackupCode({code: "j1rFA-Z3tNz"}, {
onSuccess(){
console.log("Success")
//redirect the user on success
},
onError(ctx){
alert(ctx.error.message)
}
})
};
Can i fix this somehow ?
No description
20 Replies
KiNFiSH
KiNFiSH•2w ago
ig the error occurs because you're trying to use a hardcoded backup code "j1rFA-Z3tNz" which doesn't match the expected format. you might need to generate backup codes for your user. You can do this by calling the generateBackupCodes.
wvn
wvnOP•2w ago
i will try it tomorrow
wvn
wvnOP•2w ago
Im gettingn2FA codes from enable like data.backuoCodes Is that correct?
No description
wvn
wvnOP•2w ago
so the thing here is: should i push the backup code with the score ( like this XXXX-XXXX ) Or without? XXXXXXXX
KiNFiSH
KiNFiSH•2w ago
function generateBackupCodesFn(options?: BackupCodeOptions) {
return Array.from({ length: options?.amount ?? 10 })
.fill(null)
.map(() => generateRandomString(options?.length ?? 10, "a-z", "0-9", "A-Z"))
.map((code) => `${code.slice(0, 5)}-${code.slice(5)}`);
}
function generateBackupCodesFn(options?: BackupCodeOptions) {
return Array.from({ length: options?.amount ?? 10 })
.fill(null)
.map(() => generateRandomString(options?.length ?? 10, "a-z", "0-9", "A-Z"))
.map((code) => `${code.slice(0, 5)}-${code.slice(5)}`);
}
export interface BackupCodeOptions {
/**
* The amount of backup codes to generate
*
* @default 10
*/
amount?: number;
/**
* The length of the backup codes
*
* @default 10
*/
length?: number;
customBackupCodesGenerate?: () => string[];
}
export interface BackupCodeOptions {
/**
* The amount of backup codes to generate
*
* @default 10
*/
amount?: number;
/**
* The length of the backup codes
*
* @default 10
*/
length?: number;
customBackupCodesGenerate?: () => string[];
}
you can also enable to use the custom one as well if you wish
wvn
wvnOP•2w ago
That code is for generating.. But if i wanna check it i do
await authClient.twoFactor.verifyBackupCode({code: "j1rFA-Z3tNz"}, {
onSuccess(){
console.log("Success")
//redirect the user on success
},
onError(ctx){
alert(ctx.error.message)
}
})
await authClient.twoFactor.verifyBackupCode({code: "j1rFA-Z3tNz"}, {
onSuccess(){
console.log("Success")
//redirect the user on success
},
onError(ctx){
alert(ctx.error.message)
}
})
I do this ?
KiNFiSH
KiNFiSH•2w ago
I mean generating with some format makes it easier on verifying it later
wvn
wvnOP•2w ago
Okay i will try to do this
wvn
wvnOP•2w ago
i mean the generating works. But the checking for the codes. Do i somehow need to save them in database or just default like it is in the docs ?
No description
KiNFiSH
KiNFiSH•2w ago
Just default like the docs
wvn
wvnOP•2w ago
Just wondering.. What is this ?
customBackupCodesGenerate?: () => string[];
customBackupCodesGenerate?: () => string[];
await authClient.twoFactor.verifyBackupCode({code: "N5stL-xDSAJ"}, {
onSuccess(){
console.log("Success")
//redirect the user on success
},
onError(ctx){
alert(ctx.error.message)
}
})
await authClient.twoFactor.verifyBackupCode({code: "N5stL-xDSAJ"}, {
onSuccess(){
console.log("Success")
//redirect the user on success
},
onError(ctx){
alert(ctx.error.message)
}
})
# SERVER_ERROR: Error: padded hex string expected, got unpadded hex of length 191
at hexToBytes (../src/utils.ts:56:20)
POST /api/auth/two-factor/verify-backup-code 500 in 237ms
# SERVER_ERROR: Error: padded hex string expected, got unpadded hex of length 191
at hexToBytes (../src/utils.ts:56:20)
POST /api/auth/two-factor/verify-backup-code 500 in 237ms
undefined
undefined
wvn
wvnOP•2w ago
any idea ?
No description
KiNFiSH
KiNFiSH•2w ago
This is for you to do a custom backup codes
wvn
wvnOP•2w ago
And for the error ?
KiNFiSH
KiNFiSH•2w ago
How are you generating it Like the code snippets
wvn
wvnOP•2w ago
The backup codes ?
KiNFiSH
KiNFiSH•2w ago
Yeah
wvn
wvnOP•2w ago
Yeah gemme minute my server is having big problems rn. Give me 5 minutes
const [backupCodes, setBackupCodes] = useState<string[]>([]);

function generateBackupCodesFn(options?: BackupCodeOptions) {
return Array.from({ length: options?.amount ?? 10 })
.fill(null)
.map(() => generateRandomString(options?.length ?? 10, "a-z", "0-9", "A-Z"))
.map((code) => `${code.slice(0, 5)}-${code.slice(5)}`);
}
setBackupCodes(generateBackupCodesFn());

<div className="grid grid-cols-2 gap-2">
{backupCodes.map((code, index) => (
<code key={index} className="text-sm font-mono">{code}</code>
))}
</div>
const [backupCodes, setBackupCodes] = useState<string[]>([]);

function generateBackupCodesFn(options?: BackupCodeOptions) {
return Array.from({ length: options?.amount ?? 10 })
.fill(null)
.map(() => generateRandomString(options?.length ?? 10, "a-z", "0-9", "A-Z"))
.map((code) => `${code.slice(0, 5)}-${code.slice(5)}`);
}
setBackupCodes(generateBackupCodesFn());

<div className="grid grid-cols-2 gap-2">
{backupCodes.map((code, index) => (
<code key={index} className="text-sm font-mono">{code}</code>
))}
</div>
KiNFiSH
KiNFiSH•2w ago
You can use the internal generateCode and pls refer to this internal test and lemme know if does not work for you - https://github.com/better-auth/better-auth/blob/main/packages%2Fbetter-auth%2Fsrc%2Fplugins%2Ftwo-factor%2Ftwo-factor.test.ts#L167-L244
GitHub
better-auth/packages/better-auth/src/plugins/two-factor/two-factor....
The most comprehensive authentication framework for TypeScript - better-auth/better-auth
wvn
wvnOP•7d ago
yeah i will test this tomorrow šŸ˜„ i forgot about this One think. Im redoing the whole auth system. Should i authenticate users at server on client ?
# SERVER_ERROR: [Error [PrismaClientValidationError]:
Invalid `db[getModelName(model)].update()` invocation in
C:\Users\Admin\Desktop\LicensingWeb\my-app\.next\server\chunks\node_modules_better-auth_dist_e7fe42cb._.js:3190:62

3187 }
3188 const whereClause = convertWhereClause(model, where);
3189 const transformed = transformInput(update, model, "update");
→ 3190 const result = await db[getModelName(model)].update({
where: {
userId: "fa7vk3x8buBzHuwEecxPfelVvbPZEC9z",
? id?: String,
? AND?: TwoFactorWhereInput | TwoFactorWhereInput[],
? OR?: TwoFactorWhereInput[],
? NOT?: TwoFactorWhereInput | TwoFactorWhereInput[],
? secret?: StringFilter | String,
? backupCodes?: StringFilter | String,
? user?: UserScalarRelationFilter | UserWhereInput
},
data: {
backupCodes: "10bca1f7ea07176943d196cc5af8a935f852edd4cfec3c233f06d28bb80ee049aa9fd955130a1f85f3a6a85f95d6601724c21bea97e292dbaf3ddf8ceaf002226e26482345810211383e14c16bca8aa4699d13983f21618e16a0f483899c201f906f33bae7bd1345b56da3572258db6d78abace6165433c30596969c2afa1b62d59bf0427b5a8f61ecb1ee5124585c0728eb82787316aad1bbe3625237a1225d833a1babb85b5d3befd79c3c0a83dd6c83a404c968"
}
})

Argument `where` of type TwoFactorWhereUniqueInput needs at least one of `id` arguments. Available options are marked with ?.] {
clientVersion: '6.6.0'
}
# SERVER_ERROR: [Error [PrismaClientValidationError]:
Invalid `db[getModelName(model)].update()` invocation in
C:\Users\Admin\Desktop\LicensingWeb\my-app\.next\server\chunks\node_modules_better-auth_dist_e7fe42cb._.js:3190:62

3187 }
3188 const whereClause = convertWhereClause(model, where);
3189 const transformed = transformInput(update, model, "update");
→ 3190 const result = await db[getModelName(model)].update({
where: {
userId: "fa7vk3x8buBzHuwEecxPfelVvbPZEC9z",
? id?: String,
? AND?: TwoFactorWhereInput | TwoFactorWhereInput[],
? OR?: TwoFactorWhereInput[],
? NOT?: TwoFactorWhereInput | TwoFactorWhereInput[],
? secret?: StringFilter | String,
? backupCodes?: StringFilter | String,
? user?: UserScalarRelationFilter | UserWhereInput
},
data: {
backupCodes: "10bca1f7ea07176943d196cc5af8a935f852edd4cfec3c233f06d28bb80ee049aa9fd955130a1f85f3a6a85f95d6601724c21bea97e292dbaf3ddf8ceaf002226e26482345810211383e14c16bca8aa4699d13983f21618e16a0f483899c201f906f33bae7bd1345b56da3572258db6d78abace6165433c30596969c2afa1b62d59bf0427b5a8f61ecb1ee5124585c0728eb82787316aad1bbe3625237a1225d833a1babb85b5d3befd79c3c0a83dd6c83a404c968"
}
})

Argument `where` of type TwoFactorWhereUniqueInput needs at least one of `id` arguments. Available options are marked with ?.] {
clientVersion: '6.6.0'
}
Do you know why ?
try {
const { data, error } = await authClient.twoFactor.verifyTotp({
code: verificationCode
});

if (error) {
toast.error("Invalid verification code. Please try again.");
return;
}

// If verification is successful, generate backup codes
const backupCodesRes = await authClient.twoFactor.generateBackupCodes({
password: password
});

if (backupCodesRes.data?.backupCodes) {
setBackupCodes(backupCodesRes.data?.backupCodes || []);
setCurrentStep(3);
}
} catch (error) {
console.error("Error during verification:", error);
toast.error("Failed to verify code. Please try again.");
}
try {
const { data, error } = await authClient.twoFactor.verifyTotp({
code: verificationCode
});

if (error) {
toast.error("Invalid verification code. Please try again.");
return;
}

// If verification is successful, generate backup codes
const backupCodesRes = await authClient.twoFactor.generateBackupCodes({
password: password
});

if (backupCodesRes.data?.backupCodes) {
setBackupCodes(backupCodesRes.data?.backupCodes || []);
setCurrentStep(3);
}
} catch (error) {
console.error("Error during verification:", error);
toast.error("Failed to verify code. Please try again.");
}

Did you find this page helpful?