Skip to content

Commit f7755cb

Browse files
committed
feat: add delete-account Cloud Function for permanent user auth deletion
Closes #758. The client-side Appwrite SDK has no hard-delete endpoint for auth accounts. This server-side Cloud Function calls the Appwrite Users API (users.deleteUser) to permanently remove the auth record after the Flutter app has already cleaned up the profile doc, username doc, and profile picture. Appwrite cascade relationships handle followers/friends automatically. The function is secured by reading x-appwrite-user-id from the request header, which Appwrite sets automatically when an authenticated user invokes a function, ensuring users can only delete their own account. Related Flutter PR: AOSSIE-Org/Resonate#786
1 parent 795f29b commit f7755cb

File tree

4 files changed

+91
-0
lines changed

4 files changed

+91
-0
lines changed

appwrite.json

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,31 @@
515515
"entrypoint": "src/main.js",
516516
"commands": "npm install",
517517
"path": "functions/sync-all-documents-with-meilisearch"
518+
},
519+
{
520+
"$id": "delete-account",
521+
"name": "Delete Account",
522+
"runtime": "node-16.0",
523+
"path": "functions/delete-account",
524+
"entrypoint": "src/main.js",
525+
"ignore": [
526+
"node_modules",
527+
".npm"
528+
],
529+
"vars": [],
530+
"execute": [
531+
"users"
532+
],
533+
"events": [],
534+
"schedule": "",
535+
"timeout": 15,
536+
"commands": "npm install",
537+
"enabled": true,
538+
"logging": true,
539+
"scopes": [
540+
"users.read",
541+
"users.write"
542+
]
518543
}
519544
],
520545
"buckets": [
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"name": "delete-account",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "src/main.js",
6+
"type": "module",
7+
"scripts": {
8+
"start": "node src/main.js",
9+
"format": "prettier --write ."
10+
},
11+
"dependencies": {
12+
"node-appwrite": "^17.0.0"
13+
},
14+
"devDependencies": {
15+
"prettier": "^3.0.0"
16+
}
17+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { Client, Users } from 'node-appwrite';
2+
import { throwIfMissing } from './utils.js';
3+
4+
export default async ({ req, res, log, error }) => {
5+
throwIfMissing(process.env, ['APPWRITE_API_KEY']);
6+
7+
// Appwrite automatically sets x-appwrite-user-id when an authenticated
8+
// user invokes a function — use this to ensure users can only delete
9+
// their own account.
10+
const userId = req.headers['x-appwrite-user-id'];
11+
if (!userId) {
12+
return res.json({ message: 'Unauthorized: no user session found' }, 401);
13+
}
14+
15+
const client = new Client()
16+
.setEndpoint(
17+
process.env.APPWRITE_ENDPOINT ?? 'https://cloud.appwrite.io/v1'
18+
)
19+
.setProject(process.env.APPWRITE_FUNCTION_PROJECT_ID)
20+
.setKey(process.env.APPWRITE_API_KEY);
21+
22+
try {
23+
log(`Deleting auth account for user: ${userId}`);
24+
25+
// Hard-delete the Appwrite auth account. This is only possible
26+
// server-side via the Users API — the client SDK has no equivalent.
27+
// The client-side already handles: profile picture, user doc,
28+
// username doc. Appwrite cascade relationships handle: followers, friends.
29+
await new Users(client).deleteUser(userId);
30+
31+
log(`Auth account deleted successfully for user: ${userId}`);
32+
} catch (e) {
33+
error(String(e));
34+
return res.json({ message: String(e) }, 500);
35+
}
36+
37+
return res.json({ message: 'Account permanently deleted' });
38+
};
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
export const throwIfMissing = (obj, keys) => {
2+
const missing = [];
3+
for (let key of keys) {
4+
if (!(key in obj) || !obj[key]) {
5+
missing.push(key);
6+
}
7+
}
8+
if (missing.length > 0) {
9+
throw new Error(`Missing required fields: ${missing.join(', ')}`);
10+
}
11+
};

0 commit comments

Comments
 (0)