mirror of
https://github.com/better-auth/better-auth.git
synced 2026-05-25 16:36:34 -05:00
feat(account): add option to allow unlinking all accounts (#1818)
This commit is contained in:
@@ -316,7 +316,15 @@ export const auth = betterAuth({
|
||||
|
||||
- `modelName`: The model name for the account
|
||||
- `fields`: Map fields to different column names
|
||||
- `accountLinking`: Configuration for account linking
|
||||
|
||||
### `accountLinking`
|
||||
|
||||
Configuration for account linking.
|
||||
|
||||
- `enabled`: Enable account linking (default: `false`)
|
||||
- `trustedProviders`: List of trusted providers
|
||||
- `allowDifferentEmails`: Allow users to link accounts with different email addresses
|
||||
- `allowUnlinkingAll`: Allow users to unlink all accounts
|
||||
|
||||
## `verification`
|
||||
|
||||
|
||||
@@ -59,6 +59,8 @@ describe("account", async () => {
|
||||
},
|
||||
});
|
||||
|
||||
const ctx = await auth.$context;
|
||||
|
||||
const { headers } = await signInWithTestUser();
|
||||
|
||||
it("should list all accounts", async () => {
|
||||
@@ -198,6 +200,15 @@ describe("account", async () => {
|
||||
headers,
|
||||
},
|
||||
});
|
||||
await ctx.adapter.delete({
|
||||
model: "account",
|
||||
where: [
|
||||
{
|
||||
field: "providerId",
|
||||
value: "google",
|
||||
},
|
||||
],
|
||||
});
|
||||
const unlinkAccountId = previousAccounts.data![0].accountId;
|
||||
const unlinkRes = await client.unlinkAccount({
|
||||
providerId: "credential",
|
||||
|
||||
@@ -184,17 +184,14 @@ export const unlinkAccount = createAuthEndpoint(
|
||||
message: BASE_ERROR_CODES.ACCOUNT_NOT_FOUND,
|
||||
});
|
||||
}
|
||||
|
||||
const remainingAccounts = accounts.filter(
|
||||
(account) => account.providerId === ctx.body.providerId,
|
||||
);
|
||||
|
||||
if (remainingAccounts.length === 1) {
|
||||
if (
|
||||
accounts.length === 1 &&
|
||||
!ctx.context.options.account?.accountLinking?.allowUnlinkingAll
|
||||
) {
|
||||
throw new APIError("BAD_REQUEST", {
|
||||
message: BASE_ERROR_CODES.FAILED_TO_UNLINK_LAST_ACCOUNT,
|
||||
});
|
||||
}
|
||||
|
||||
await ctx.context.internalAdapter.deleteAccount(accountExist.id);
|
||||
return ctx.json({
|
||||
status: true,
|
||||
|
||||
@@ -440,6 +440,12 @@ export type BetterAuthOptions = {
|
||||
* ⚠️ Warning: enabling this might lead to account takeovers, so proceed with caution.
|
||||
*/
|
||||
allowDifferentEmails?: boolean;
|
||||
/**
|
||||
* If enabled (true), this will allow users to unlink all accounts.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
allowUnlinkingAll?: boolean;
|
||||
};
|
||||
};
|
||||
/**
|
||||
|
||||
@@ -1,20 +1,25 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"declaration": true,
|
||||
"emitDeclarationOnly": true,
|
||||
"declarationMap": true,
|
||||
"outDir": "dist",
|
||||
"noEmit": false,
|
||||
"composite": false,
|
||||
"target": "es2022",
|
||||
"allowJs": true,
|
||||
"resolveJsonModule": true,
|
||||
"module": "ESNext",
|
||||
"noEmit": true,
|
||||
"incremental": true,
|
||||
"moduleResolution": "Bundler",
|
||||
"moduleDetection": "force",
|
||||
"isolatedModules": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"strict": true,
|
||||
"noImplicitOverride": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
"moduleDetection": "force",
|
||||
"module": "Preserve",
|
||||
"skipLibCheck": true,
|
||||
"types": ["node"],
|
||||
"isolatedModules": true,
|
||||
"tsBuildInfoFile": ".tsbuildinfo",
|
||||
"preserveSymlinks": true,
|
||||
"noImplicitOverride": true
|
||||
},
|
||||
"exclude": ["node_modules"],
|
||||
"include": ["src"]
|
||||
"exclude": ["node_modules", "dist"],
|
||||
"references": [],
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user