summary refs log tree commit diff
diff options
context:
space:
mode:
authorPuyodead1 <puyodead@protonmail.com>2023-02-24 01:54:10 -0500
committerPuyodead1 <puyodead@protonmail.com>2023-02-24 01:54:10 -0500
commit05453ec14880732c5d0d20fd3575bb2b3952760d (patch)
treec3b7272d7eafff2e988702b9bf3b93f24a101881
parentadd SendGrid transport (diff)
downloadserver-05453ec14880732c5d0d20fd3575bb2b3952760d.tar.xz
implement password reset
-rw-r--r--assets/email_templates/new_login_location.html2
-rw-r--r--assets/email_templates/password_reset_request.html2
-rw-r--r--assets/email_templates/verify_email.html2
-rw-r--r--assets/locales/en/auth.json4
-rw-r--r--assets/schemas.json2543
-rw-r--r--src/api/middlewares/Authentication.ts2
-rw-r--r--src/api/routes/auth/forgot.ts92
-rw-r--r--src/api/routes/auth/reset.ts57
-rw-r--r--src/api/routes/auth/verify/resend.ts2
-rw-r--r--src/util/config/Config.ts3
-rw-r--r--src/util/config/types/PasswordResetConfiguration.ts21
-rw-r--r--src/util/config/types/index.ts1
-rw-r--r--src/util/entities/User.ts2
-rw-r--r--src/util/schemas/ForgotPasswordSchema.ts22
-rw-r--r--src/util/schemas/PasswordResetSchema.ts22
-rw-r--r--src/util/schemas/index.ts20
-rw-r--r--src/util/util/Email.ts106
-rw-r--r--src/util/util/Token.ts9
18 files changed, 2198 insertions, 714 deletions
diff --git a/assets/email_templates/new_login_location.html b/assets/email_templates/new_login_location.html
index e597ac6c..ff262e99 100644
--- a/assets/email_templates/new_login_location.html
+++ b/assets/email_templates/new_login_location.html
@@ -104,7 +104,7 @@
 							Alternatively, you can directly paste this link into
 							your browser:
 						</p>
-						<a href="{verifyUrl}" target="_blank">{verifyUrl}</a>
+						<a href="{verifyUrl}" target="_blank" style="word-wrap: break-word;">{verifyUrl}</a>
 					</div>
 				</div>
 			</div>
diff --git a/assets/email_templates/password_reset_request.html b/assets/email_templates/password_reset_request.html
index ab8f4d23..b770e7ba 100644
--- a/assets/email_templates/password_reset_request.html
+++ b/assets/email_templates/password_reset_request.html
@@ -90,7 +90,7 @@
 							Alternatively, you can directly paste this link into
 							your browser:
 						</p>
-						<a href="{passwordResetUrl}" target="_blank"
+						<a href="{passwordResetUrl}" target="_blank" style="word-wrap: break-word;"
 							>{passwordResetUrl}</a
 						>
 					</div>
diff --git a/assets/email_templates/verify_email.html b/assets/email_templates/verify_email.html
index 604242c4..481a46d4 100644
--- a/assets/email_templates/verify_email.html
+++ b/assets/email_templates/verify_email.html
@@ -91,7 +91,7 @@
 							Alternatively, you can directly paste this link into
 							your browser:
 						</p>
-						<a href="{emailVerificationUrl}" target="_blank"
+						<a href="{emailVerificationUrl}" target="_blank" style="word-wrap: break-word;"
 							>{emailVerificationUrl}</a
 						>
 					</div>
diff --git a/assets/locales/en/auth.json b/assets/locales/en/auth.json
index 2178548e..0521a902 100644
--- a/assets/locales/en/auth.json
+++ b/assets/locales/en/auth.json
@@ -16,5 +16,9 @@
 		"USERNAME_TOO_MANY_USERS": "Too many users have this username, please try another",
 		"GUESTS_DISABLED": "Guest users are disabled",
 		"TOO_MANY_REGISTRATIONS": "Too many registrations, please try again later"
+	},
+	"password_reset": {
+		"EMAIL_DOES_NOT_EXIST": "Email does not exist.",
+		"INVALID_TOKEN": "Invalid token."
 	}
 }
diff --git a/assets/schemas.json b/assets/schemas.json
index 2bfb525d..1fdfa361 100644
--- a/assets/schemas.json
+++ b/assets/schemas.json
@@ -4584,6 +4584,599 @@
         },
         "$schema": "http://json-schema.org/draft-07/schema#"
     },
+    "ForgotPasswordSchema": {
+        "type": "object",
+        "properties": {
+            "login": {
+                "type": "string"
+            },
+            "captcha_key": {
+                "type": "string"
+            }
+        },
+        "additionalProperties": false,
+        "required": [
+            "login"
+        ],
+        "definitions": {
+            "ChannelPermissionOverwriteType": {
+                "enum": [
+                    0,
+                    1,
+                    2
+                ],
+                "type": "number"
+            },
+            "ChannelModifySchema": {
+                "type": "object",
+                "properties": {
+                    "name": {
+                        "maxLength": 100,
+                        "type": "string"
+                    },
+                    "type": {
+                        "enum": [
+                            0,
+                            1,
+                            10,
+                            11,
+                            12,
+                            13,
+                            14,
+                            15,
+                            2,
+                            255,
+                            3,
+                            33,
+                            34,
+                            35,
+                            4,
+                            5,
+                            6,
+                            64,
+                            7,
+                            8,
+                            9
+                        ],
+                        "type": "number"
+                    },
+                    "topic": {
+                        "type": "string"
+                    },
+                    "icon": {
+                        "type": [
+                            "null",
+                            "string"
+                        ]
+                    },
+                    "bitrate": {
+                        "type": "integer"
+                    },
+                    "user_limit": {
+                        "type": "integer"
+                    },
+                    "rate_limit_per_user": {
+                        "type": "integer"
+                    },
+                    "position": {
+                        "type": "integer"
+                    },
+                    "permission_overwrites": {
+                        "type": "array",
+                        "items": {
+                            "type": "object",
+                            "properties": {
+                                "id": {
+                                    "type": "string"
+                                },
+                                "type": {
+                                    "$ref": "#/definitions/ChannelPermissionOverwriteType"
+                                },
+                                "allow": {
+                                    "type": "string"
+                                },
+                                "deny": {
+                                    "type": "string"
+                                }
+                            },
+                            "additionalProperties": false,
+                            "required": [
+                                "allow",
+                                "deny",
+                                "id",
+                                "type"
+                            ]
+                        }
+                    },
+                    "parent_id": {
+                        "type": "string"
+                    },
+                    "id": {
+                        "type": "string"
+                    },
+                    "nsfw": {
+                        "type": "boolean"
+                    },
+                    "rtc_region": {
+                        "type": "string"
+                    },
+                    "default_auto_archive_duration": {
+                        "type": "integer"
+                    },
+                    "default_reaction_emoji": {
+                        "type": [
+                            "null",
+                            "string"
+                        ]
+                    },
+                    "flags": {
+                        "type": "integer"
+                    },
+                    "default_thread_rate_limit_per_user": {
+                        "type": "integer"
+                    },
+                    "video_quality_mode": {
+                        "type": "integer"
+                    }
+                },
+                "additionalProperties": false
+            },
+            "ActivitySchema": {
+                "type": "object",
+                "properties": {
+                    "afk": {
+                        "type": "boolean"
+                    },
+                    "status": {
+                        "$ref": "#/definitions/Status"
+                    },
+                    "activities": {
+                        "type": "array",
+                        "items": {
+                            "$ref": "#/definitions/Activity"
+                        }
+                    },
+                    "since": {
+                        "type": "integer"
+                    }
+                },
+                "additionalProperties": false,
+                "required": [
+                    "status"
+                ]
+            },
+            "Status": {
+                "enum": [
+                    "dnd",
+                    "idle",
+                    "invisible",
+                    "offline",
+                    "online"
+                ],
+                "type": "string"
+            },
+            "Activity": {
+                "type": "object",
+                "properties": {
+                    "name": {
+                        "type": "string"
+                    },
+                    "type": {
+                        "$ref": "#/definitions/ActivityType"
+                    },
+                    "url": {
+                        "type": "string"
+                    },
+                    "created_at": {
+                        "type": "integer"
+                    },
+                    "timestamps": {
+                        "type": "object",
+                        "properties": {
+                            "start": {
+                                "type": "integer"
+                            },
+                            "end": {
+                                "type": "integer"
+                            }
+                        },
+                        "additionalProperties": false,
+                        "required": [
+                            "end",
+                            "start"
+                        ]
+                    },
+                    "application_id": {
+                        "type": "string"
+                    },
+                    "details": {
+                        "type": "string"
+                    },
+                    "state": {
+                        "type": "string"
+                    },
+                    "emoji": {
+                        "type": "object",
+                        "properties": {
+                            "name": {
+                                "type": "string"
+                            },
+                            "id": {
+                                "type": "string"
+                            },
+                            "animated": {
+                                "type": "boolean"
+                            }
+                        },
+                        "additionalProperties": false,
+                        "required": [
+                            "animated",
+                            "name"
+                        ]
+                    },
+                    "party": {
+                        "type": "object",
+                        "properties": {
+                            "id": {
+                                "type": "string"
+                            },
+                            "size": {
+                                "type": "array",
+                                "items": [
+                                    {
+                                        "type": "integer"
+                                    }
+                                ],
+                                "minItems": 1,
+                                "maxItems": 1
+                            }
+                        },
+                        "additionalProperties": false
+                    },
+                    "assets": {
+                        "type": "object",
+                        "properties": {
+                            "large_image": {
+                                "type": "string"
+                            },
+                            "large_text": {
+                                "type": "string"
+                            },
+                            "small_image": {
+                                "type": "string"
+                            },
+                            "small_text": {
+                                "type": "string"
+                            }
+                        },
+                        "additionalProperties": false
+                    },
+                    "secrets": {
+                        "type": "object",
+                        "properties": {
+                            "join": {
+                                "type": "string"
+                            },
+                            "spectate": {
+                                "type": "string"
+                            },
+                            "match": {
+                                "type": "string"
+                            }
+                        },
+                        "additionalProperties": false
+                    },
+                    "instance": {
+                        "type": "boolean"
+                    },
+                    "flags": {
+                        "type": "string"
+                    },
+                    "id": {
+                        "type": "string"
+                    },
+                    "sync_id": {
+                        "type": "string"
+                    },
+                    "metadata": {
+                        "type": "object",
+                        "properties": {
+                            "context_uri": {
+                                "type": "string"
+                            },
+                            "album_id": {
+                                "type": "string"
+                            },
+                            "artist_ids": {
+                                "type": "array",
+                                "items": {
+                                    "type": "string"
+                                }
+                            }
+                        },
+                        "additionalProperties": false,
+                        "required": [
+                            "album_id",
+                            "artist_ids"
+                        ]
+                    },
+                    "session_id": {
+                        "type": "string"
+                    }
+                },
+                "additionalProperties": false,
+                "required": [
+                    "flags",
+                    "name",
+                    "session_id",
+                    "type"
+                ]
+            },
+            "ActivityType": {
+                "enum": [
+                    0,
+                    1,
+                    2,
+                    4,
+                    5
+                ],
+                "type": "number"
+            },
+            "Record<string,[number,number][]>": {
+                "type": "object",
+                "additionalProperties": false
+            },
+            "Embed": {
+                "type": "object",
+                "properties": {
+                    "title": {
+                        "type": "string"
+                    },
+                    "type": {
+                        "enum": [
+                            "article",
+                            "gifv",
+                            "image",
+                            "link",
+                            "rich",
+                            "video"
+                        ],
+                        "type": "string"
+                    },
+                    "description": {
+                        "type": "string"
+                    },
+                    "url": {
+                        "type": "string"
+                    },
+                    "timestamp": {
+                        "type": "string",
+                        "format": "date-time"
+                    },
+                    "color": {
+                        "type": "integer"
+                    },
+                    "footer": {
+                        "type": "object",
+                        "properties": {
+                            "text": {
+                                "type": "string"
+                            },
+                            "icon_url": {
+                                "type": "string"
+                            },
+                            "proxy_icon_url": {
+                                "type": "string"
+                            }
+                        },
+                        "additionalProperties": false,
+                        "required": [
+                            "text"
+                        ]
+                    },
+                    "image": {
+                        "$ref": "#/definitions/EmbedImage"
+                    },
+                    "thumbnail": {
+                        "$ref": "#/definitions/EmbedImage"
+                    },
+                    "video": {
+                        "$ref": "#/definitions/EmbedImage"
+                    },
+                    "provider": {
+                        "type": "object",
+                        "properties": {
+                            "name": {
+                                "type": "string"
+                            },
+                            "url": {
+                                "type": "string"
+                            }
+                        },
+                        "additionalProperties": false
+                    },
+                    "author": {
+                        "type": "object",
+                        "properties": {
+                            "name": {
+                                "type": "string"
+                            },
+                            "url": {
+                                "type": "string"
+                            },
+                            "icon_url": {
+                                "type": "string"
+                            },
+                            "proxy_icon_url": {
+                                "type": "string"
+                            }
+                        },
+                        "additionalProperties": false
+                    },
+                    "fields": {
+                        "type": "array",
+                        "items": {
+                            "type": "object",
+                            "properties": {
+                                "name": {
+                                    "type": "string"
+                                },
+                                "value": {
+                                    "type": "string"
+                                },
+                                "inline": {
+                                    "type": "boolean"
+                                }
+                            },
+                            "additionalProperties": false,
+                            "required": [
+                                "name",
+                                "value"
+                            ]
+                        }
+                    }
+                },
+                "additionalProperties": false
+            },
+            "EmbedImage": {
+                "type": "object",
+                "properties": {
+                    "url": {
+                        "type": "string"
+                    },
+                    "proxy_url": {
+                        "type": "string"
+                    },
+                    "height": {
+                        "type": "integer"
+                    },
+                    "width": {
+                        "type": "integer"
+                    }
+                },
+                "additionalProperties": false
+            },
+            "Partial<ChannelOverride>": {
+                "type": "object",
+                "properties": {
+                    "message_notifications": {
+                        "type": "integer"
+                    },
+                    "mute_config": {
+                        "$ref": "#/definitions/MuteConfig"
+                    },
+                    "muted": {
+                        "type": "boolean"
+                    },
+                    "channel_id": {
+                        "type": [
+                            "null",
+                            "string"
+                        ]
+                    }
+                },
+                "additionalProperties": false
+            },
+            "MuteConfig": {
+                "type": "object",
+                "properties": {
+                    "end_time": {
+                        "type": "integer"
+                    },
+                    "selected_time_window": {
+                        "type": "integer"
+                    }
+                },
+                "additionalProperties": false,
+                "required": [
+                    "end_time",
+                    "selected_time_window"
+                ]
+            },
+            "CustomStatus": {
+                "type": "object",
+                "properties": {
+                    "emoji_id": {
+                        "type": "string"
+                    },
+                    "emoji_name": {
+                        "type": "string"
+                    },
+                    "expires_at": {
+                        "type": "integer"
+                    },
+                    "text": {
+                        "type": "string"
+                    }
+                },
+                "additionalProperties": false
+            },
+            "FriendSourceFlags": {
+                "type": "object",
+                "properties": {
+                    "all": {
+                        "type": "boolean"
+                    }
+                },
+                "additionalProperties": false,
+                "required": [
+                    "all"
+                ]
+            },
+            "GuildFolder": {
+                "type": "object",
+                "properties": {
+                    "color": {
+                        "type": "integer"
+                    },
+                    "guild_ids": {
+                        "type": "array",
+                        "items": {
+                            "type": "string"
+                        }
+                    },
+                    "id": {
+                        "type": "integer"
+                    },
+                    "name": {
+                        "type": "string"
+                    }
+                },
+                "additionalProperties": false,
+                "required": [
+                    "color",
+                    "guild_ids",
+                    "id",
+                    "name"
+                ]
+            },
+            "Partial<GenerateWebAuthnCredentialsSchema>": {
+                "type": "object",
+                "properties": {
+                    "password": {
+                        "type": "string"
+                    }
+                },
+                "additionalProperties": false
+            },
+            "Partial<CreateWebAuthnCredentialSchema>": {
+                "type": "object",
+                "properties": {
+                    "credential": {
+                        "type": "string"
+                    },
+                    "name": {
+                        "type": "string"
+                    },
+                    "ticket": {
+                        "type": "string"
+                    }
+                },
+                "additionalProperties": false
+            }
+        },
+        "$schema": "http://json-schema.org/draft-07/schema#"
+    },
     "GuildCreateSchema": {
         "type": "object",
         "properties": {
@@ -12155,20 +12748,125 @@
         },
         "$schema": "http://json-schema.org/draft-07/schema#"
     },
-    "MfaCodesSchema": {
+    "MessageEditSchema": {
         "type": "object",
         "properties": {
-            "password": {
+            "file": {
+                "type": "object",
+                "properties": {
+                    "filename": {
+                        "type": "string"
+                    }
+                },
+                "additionalProperties": false,
+                "required": [
+                    "filename"
+                ]
+            },
+            "embed": {
+                "$ref": "#/definitions/Embed"
+            },
+            "flags": {
                 "type": "string"
             },
-            "regenerate": {
+            "content": {
+                "type": "string"
+            },
+            "nonce": {
+                "type": "string"
+            },
+            "channel_id": {
+                "type": "string"
+            },
+            "tts": {
                 "type": "boolean"
+            },
+            "embeds": {
+                "type": "array",
+                "items": {
+                    "$ref": "#/definitions/Embed"
+                }
+            },
+            "allowed_mentions": {
+                "type": "object",
+                "properties": {
+                    "parse": {
+                        "type": "array",
+                        "items": {
+                            "type": "string"
+                        }
+                    },
+                    "roles": {
+                        "type": "array",
+                        "items": {
+                            "type": "string"
+                        }
+                    },
+                    "users": {
+                        "type": "array",
+                        "items": {
+                            "type": "string"
+                        }
+                    },
+                    "replied_user": {
+                        "type": "boolean"
+                    }
+                },
+                "additionalProperties": false
+            },
+            "message_reference": {
+                "type": "object",
+                "properties": {
+                    "message_id": {
+                        "type": "string"
+                    },
+                    "channel_id": {
+                        "type": "string"
+                    },
+                    "guild_id": {
+                        "type": "string"
+                    },
+                    "fail_if_not_exists": {
+                        "type": "boolean"
+                    }
+                },
+                "additionalProperties": false,
+                "required": [
+                    "channel_id",
+                    "message_id"
+                ]
+            },
+            "payload_json": {
+                "type": "string"
+            },
+            "attachments": {
+                "description": "TODO: we should create an interface for attachments\nTODO: OpenWAAO<-->attachment-style metadata conversion",
+                "type": "array",
+                "items": {
+                    "type": "object",
+                    "properties": {
+                        "id": {
+                            "type": "string"
+                        },
+                        "filename": {
+                            "type": "string"
+                        }
+                    },
+                    "additionalProperties": false,
+                    "required": [
+                        "filename",
+                        "id"
+                    ]
+                }
+            },
+            "sticker_ids": {
+                "type": "array",
+                "items": {
+                    "type": "string"
+                }
             }
         },
         "additionalProperties": false,
-        "required": [
-            "password"
-        ],
         "definitions": {
             "ChannelPermissionOverwriteType": {
                 "enum": [
@@ -12748,27 +13446,19 @@
         },
         "$schema": "http://json-schema.org/draft-07/schema#"
     },
-    "ModifyGuildStickerSchema": {
+    "MfaCodesSchema": {
         "type": "object",
         "properties": {
-            "name": {
-                "minLength": 2,
-                "maxLength": 30,
-                "type": "string"
-            },
-            "description": {
-                "maxLength": 100,
+            "password": {
                 "type": "string"
             },
-            "tags": {
-                "maxLength": 200,
-                "type": "string"
+            "regenerate": {
+                "type": "boolean"
             }
         },
         "additionalProperties": false,
         "required": [
-            "name",
-            "tags"
+            "password"
         ],
         "definitions": {
             "ChannelPermissionOverwriteType": {
@@ -13349,20 +14039,27 @@
         },
         "$schema": "http://json-schema.org/draft-07/schema#"
     },
-    "PurgeSchema": {
+    "ModifyGuildStickerSchema": {
         "type": "object",
         "properties": {
-            "before": {
+            "name": {
+                "minLength": 2,
+                "maxLength": 30,
                 "type": "string"
             },
-            "after": {
+            "description": {
+                "maxLength": 100,
+                "type": "string"
+            },
+            "tags": {
+                "maxLength": 200,
                 "type": "string"
             }
         },
         "additionalProperties": false,
         "required": [
-            "after",
-            "before"
+            "name",
+            "tags"
         ],
         "definitions": {
             "ChannelPermissionOverwriteType": {
@@ -13943,49 +14640,20 @@
         },
         "$schema": "http://json-schema.org/draft-07/schema#"
     },
-    "RegisterSchema": {
+    "PasswordResetSchema": {
         "type": "object",
         "properties": {
-            "username": {
-                "minLength": 2,
-                "maxLength": 32,
-                "type": "string"
-            },
             "password": {
-                "minLength": 1,
-                "maxLength": 72,
                 "type": "string"
             },
-            "consent": {
-                "type": "boolean"
-            },
-            "email": {
-                "format": "email",
-                "type": "string"
-            },
-            "fingerprint": {
-                "type": "string"
-            },
-            "invite": {
-                "type": "string"
-            },
-            "date_of_birth": {
-                "type": "string"
-            },
-            "gift_code_sku_id": {
-                "type": "string"
-            },
-            "captcha_key": {
+            "token": {
                 "type": "string"
-            },
-            "promotional_email_opt_in": {
-                "type": "boolean"
             }
         },
         "additionalProperties": false,
         "required": [
-            "consent",
-            "username"
+            "password",
+            "token"
         ],
         "definitions": {
             "ChannelPermissionOverwriteType": {
@@ -14566,20 +15234,20 @@
         },
         "$schema": "http://json-schema.org/draft-07/schema#"
     },
-    "RelationshipPostSchema": {
+    "PurgeSchema": {
         "type": "object",
         "properties": {
-            "discriminator": {
+            "before": {
                 "type": "string"
             },
-            "username": {
+            "after": {
                 "type": "string"
             }
         },
         "additionalProperties": false,
         "required": [
-            "discriminator",
-            "username"
+            "after",
+            "before"
         ],
         "definitions": {
             "ChannelPermissionOverwriteType": {
@@ -15160,20 +15828,50 @@
         },
         "$schema": "http://json-schema.org/draft-07/schema#"
     },
-    "RelationshipPutSchema": {
+    "RegisterSchema": {
         "type": "object",
         "properties": {
-            "type": {
-                "enum": [
-                    1,
-                    2,
-                    3,
-                    4
-                ],
-                "type": "number"
+            "username": {
+                "minLength": 2,
+                "maxLength": 32,
+                "type": "string"
+            },
+            "password": {
+                "minLength": 1,
+                "maxLength": 72,
+                "type": "string"
+            },
+            "consent": {
+                "type": "boolean"
+            },
+            "email": {
+                "format": "email",
+                "type": "string"
+            },
+            "fingerprint": {
+                "type": "string"
+            },
+            "invite": {
+                "type": "string"
+            },
+            "date_of_birth": {
+                "type": "string"
+            },
+            "gift_code_sku_id": {
+                "type": "string"
+            },
+            "captcha_key": {
+                "type": "string"
+            },
+            "promotional_email_opt_in": {
+                "type": "boolean"
             }
         },
         "additionalProperties": false,
+        "required": [
+            "consent",
+            "username"
+        ],
         "definitions": {
             "ChannelPermissionOverwriteType": {
                 "enum": [
@@ -15753,35 +16451,21 @@
         },
         "$schema": "http://json-schema.org/draft-07/schema#"
     },
-    "RoleModifySchema": {
+    "RelationshipPostSchema": {
         "type": "object",
         "properties": {
-            "name": {
-                "type": "string"
-            },
-            "permissions": {
-                "type": "string"
-            },
-            "color": {
-                "type": "integer"
-            },
-            "hoist": {
-                "type": "boolean"
-            },
-            "mentionable": {
-                "type": "boolean"
-            },
-            "position": {
-                "type": "integer"
-            },
-            "icon": {
+            "discriminator": {
                 "type": "string"
             },
-            "unicode_emoji": {
+            "username": {
                 "type": "string"
             }
         },
         "additionalProperties": false,
+        "required": [
+            "discriminator",
+            "username"
+        ],
         "definitions": {
             "ChannelPermissionOverwriteType": {
                 "enum": [
@@ -16361,24 +17045,20 @@
         },
         "$schema": "http://json-schema.org/draft-07/schema#"
     },
-    "RolePositionUpdateSchema": {
-        "type": "array",
-        "items": {
-            "type": "object",
-            "properties": {
-                "id": {
-                    "type": "string"
-                },
-                "position": {
-                    "type": "integer"
-                }
-            },
-            "additionalProperties": false,
-            "required": [
-                "id",
-                "position"
-            ]
+    "RelationshipPutSchema": {
+        "type": "object",
+        "properties": {
+            "type": {
+                "enum": [
+                    1,
+                    2,
+                    3,
+                    4
+                ],
+                "type": "number"
+            }
         },
+        "additionalProperties": false,
         "definitions": {
             "ChannelPermissionOverwriteType": {
                 "enum": [
@@ -16958,98 +17638,35 @@
         },
         "$schema": "http://json-schema.org/draft-07/schema#"
     },
-    "SelectProtocolSchema": {
+    "RoleModifySchema": {
         "type": "object",
         "properties": {
-            "protocol": {
-                "enum": [
-                    "udp",
-                    "webrtc"
-                ],
+            "name": {
                 "type": "string"
             },
-            "data": {
-                "anyOf": [
-                    {
-                        "type": "object",
-                        "properties": {
-                            "address": {
-                                "type": "string"
-                            },
-                            "port": {
-                                "type": "integer"
-                            },
-                            "mode": {
-                                "type": "string"
-                            }
-                        },
-                        "additionalProperties": false,
-                        "required": [
-                            "address",
-                            "mode",
-                            "port"
-                        ]
-                    },
-                    {
-                        "type": "string"
-                    }
-                ]
-            },
-            "sdp": {
+            "permissions": {
                 "type": "string"
             },
-            "codecs": {
-                "type": "array",
-                "items": {
-                    "type": "object",
-                    "properties": {
-                        "name": {
-                            "enum": [
-                                "H264",
-                                "VP8",
-                                "VP9",
-                                "opus"
-                            ],
-                            "type": "string"
-                        },
-                        "type": {
-                            "enum": [
-                                "audio",
-                                "video"
-                            ],
-                            "type": "string"
-                        },
-                        "priority": {
-                            "type": "integer"
-                        },
-                        "payload_type": {
-                            "type": "integer"
-                        },
-                        "rtx_payload_type": {
-                            "type": [
-                                "null",
-                                "integer"
-                            ]
-                        }
-                    },
-                    "additionalProperties": false,
-                    "required": [
-                        "name",
-                        "payload_type",
-                        "priority",
-                        "type"
-                    ]
-                }
+            "color": {
+                "type": "integer"
             },
-            "rtc_connection_id": {
+            "hoist": {
+                "type": "boolean"
+            },
+            "mentionable": {
+                "type": "boolean"
+            },
+            "position": {
+                "type": "integer"
+            },
+            "icon": {
+                "type": "string"
+            },
+            "unicode_emoji": {
                 "type": "string"
             }
         },
         "additionalProperties": false,
-        "required": [
-            "data",
-            "protocol"
-        ],
         "definitions": {
             "ChannelPermissionOverwriteType": {
                 "enum": [
@@ -17629,20 +18246,24 @@
         },
         "$schema": "http://json-schema.org/draft-07/schema#"
     },
-    "TemplateCreateSchema": {
-        "type": "object",
-        "properties": {
-            "name": {
-                "type": "string"
+    "RolePositionUpdateSchema": {
+        "type": "array",
+        "items": {
+            "type": "object",
+            "properties": {
+                "id": {
+                    "type": "string"
+                },
+                "position": {
+                    "type": "integer"
+                }
             },
-            "description": {
-                "type": "string"
-            }
+            "additionalProperties": false,
+            "required": [
+                "id",
+                "position"
+            ]
         },
-        "additionalProperties": false,
-        "required": [
-            "name"
-        ],
         "definitions": {
             "ChannelPermissionOverwriteType": {
                 "enum": [
@@ -18222,19 +18843,97 @@
         },
         "$schema": "http://json-schema.org/draft-07/schema#"
     },
-    "TemplateModifySchema": {
+    "SelectProtocolSchema": {
         "type": "object",
         "properties": {
-            "name": {
+            "protocol": {
+                "enum": [
+                    "udp",
+                    "webrtc"
+                ],
                 "type": "string"
             },
-            "description": {
+            "data": {
+                "anyOf": [
+                    {
+                        "type": "object",
+                        "properties": {
+                            "address": {
+                                "type": "string"
+                            },
+                            "port": {
+                                "type": "integer"
+                            },
+                            "mode": {
+                                "type": "string"
+                            }
+                        },
+                        "additionalProperties": false,
+                        "required": [
+                            "address",
+                            "mode",
+                            "port"
+                        ]
+                    },
+                    {
+                        "type": "string"
+                    }
+                ]
+            },
+            "sdp": {
+                "type": "string"
+            },
+            "codecs": {
+                "type": "array",
+                "items": {
+                    "type": "object",
+                    "properties": {
+                        "name": {
+                            "enum": [
+                                "H264",
+                                "VP8",
+                                "VP9",
+                                "opus"
+                            ],
+                            "type": "string"
+                        },
+                        "type": {
+                            "enum": [
+                                "audio",
+                                "video"
+                            ],
+                            "type": "string"
+                        },
+                        "priority": {
+                            "type": "integer"
+                        },
+                        "payload_type": {
+                            "type": "integer"
+                        },
+                        "rtx_payload_type": {
+                            "type": [
+                                "null",
+                                "integer"
+                            ]
+                        }
+                    },
+                    "additionalProperties": false,
+                    "required": [
+                        "name",
+                        "payload_type",
+                        "priority",
+                        "type"
+                    ]
+                }
+            },
+            "rtc_connection_id": {
                 "type": "string"
             }
         },
         "additionalProperties": false,
         "required": [
-            "name"
+            "data",
+            "protocol"
         ],
         "definitions": {
             "ChannelPermissionOverwriteType": {
@@ -18815,16 +19514,19 @@
         },
         "$schema": "http://json-schema.org/draft-07/schema#"
     },
-    "TotpDisableSchema": {
+    "TemplateCreateSchema": {
         "type": "object",
         "properties": {
-            "code": {
+            "name": {
+                "type": "string"
+            },
+            "description": {
                 "type": "string"
             }
         },
         "additionalProperties": false,
         "required": [
-            "code"
+            "name"
         ],
         "definitions": {
             "ChannelPermissionOverwriteType": {
@@ -19405,22 +20107,19 @@
         },
         "$schema": "http://json-schema.org/draft-07/schema#"
     },
-    "TotpEnableSchema": {
+    "TemplateModifySchema": {
         "type": "object",
         "properties": {
-            "password": {
-                "type": "string"
-            },
-            "code": {
+            "name": {
                 "type": "string"
             },
-            "secret": {
+            "description": {
                 "type": "string"
             }
         },
         "additionalProperties": false,
         "required": [
-            "password"
+            "name"
         ],
         "definitions": {
             "ChannelPermissionOverwriteType": {
@@ -20001,32 +20700,16 @@
         },
         "$schema": "http://json-schema.org/draft-07/schema#"
     },
-    "TotpSchema": {
+    "TotpDisableSchema": {
         "type": "object",
         "properties": {
             "code": {
                 "type": "string"
-            },
-            "ticket": {
-                "type": "string"
-            },
-            "gift_code_sku_id": {
-                "type": [
-                    "null",
-                    "string"
-                ]
-            },
-            "login_source": {
-                "type": [
-                    "null",
-                    "string"
-                ]
             }
         },
         "additionalProperties": false,
         "required": [
-            "code",
-            "ticket"
+            "code"
         ],
         "definitions": {
             "ChannelPermissionOverwriteType": {
@@ -20607,16 +21290,22 @@
         },
         "$schema": "http://json-schema.org/draft-07/schema#"
     },
-    "UserDeleteSchema": {
+    "TotpEnableSchema": {
         "type": "object",
         "properties": {
-            "user_id": {
+            "password": {
+                "type": "string"
+            },
+            "code": {
+                "type": "string"
+            },
+            "secret": {
                 "type": "string"
             }
         },
         "additionalProperties": false,
         "required": [
-            "user_id"
+            "password"
         ],
         "definitions": {
             "ChannelPermissionOverwriteType": {
@@ -21197,66 +21886,33 @@
         },
         "$schema": "http://json-schema.org/draft-07/schema#"
     },
-    "UserGuildSettingsSchema": {
+    "TotpSchema": {
         "type": "object",
         "properties": {
-            "channel_overrides": {
-                "type": "object",
-                "additionalProperties": {
-                    "$ref": "#/definitions/Partial<ChannelOverride>"
-                }
+            "code": {
+                "type": "string"
             },
-            "version": {
-                "type": "integer"
+            "ticket": {
+                "type": "string"
             },
-            "guild_id": {
+            "gift_code_sku_id": {
                 "type": [
                     "null",
                     "string"
                 ]
             },
-            "flags": {
-                "type": "integer"
-            },
-            "message_notifications": {
-                "type": "integer"
-            },
-            "mobile_push": {
-                "type": "boolean"
-            },
-            "mute_config": {
-                "anyOf": [
-                    {
-                        "$ref": "#/definitions/MuteConfig"
-                    },
-                    {
-                        "type": "null"
-                    }
+            "login_source": {
+                "type": [
+                    "null",
+                    "string"
                 ]
-            },
-            "muted": {
-                "type": "boolean"
-            },
-            "suppress_everyone": {
-                "type": "boolean"
-            },
-            "suppress_roles": {
-                "type": "boolean"
-            },
-            "mute_scheduled_events": {
-                "type": "boolean"
-            },
-            "hide_muted_channels": {
-                "type": "boolean"
-            },
-            "notify_highlights": {
-                "enum": [
-                    0
-                ],
-                "type": "number"
             }
         },
         "additionalProperties": false,
+        "required": [
+            "code",
+            "ticket"
+        ],
         "definitions": {
             "ChannelPermissionOverwriteType": {
                 "enum": [
@@ -21836,52 +22492,17 @@
         },
         "$schema": "http://json-schema.org/draft-07/schema#"
     },
-    "UserModifySchema": {
+    "UserDeleteSchema": {
         "type": "object",
         "properties": {
-            "username": {
-                "minLength": 1,
-                "maxLength": 100,
-                "type": "string"
-            },
-            "avatar": {
-                "type": [
-                    "null",
-                    "string"
-                ]
-            },
-            "bio": {
-                "maxLength": 1024,
-                "type": "string"
-            },
-            "accent_color": {
-                "type": "integer"
-            },
-            "banner": {
-                "type": [
-                    "null",
-                    "string"
-                ]
-            },
-            "password": {
-                "type": "string"
-            },
-            "new_password": {
-                "type": "string"
-            },
-            "code": {
-                "type": "string"
-            },
-            "email": {
-                "type": "string"
-            },
-            "discriminator": {
-                "minLength": 4,
-                "maxLength": 4,
+            "user_id": {
                 "type": "string"
             }
         },
         "additionalProperties": false,
+        "required": [
+            "user_id"
+        ],
         "definitions": {
             "ChannelPermissionOverwriteType": {
                 "enum": [
@@ -22461,39 +23082,63 @@
         },
         "$schema": "http://json-schema.org/draft-07/schema#"
     },
-    "UserProfileModifySchema": {
+    "UserGuildSettingsSchema": {
         "type": "object",
         "properties": {
-            "bio": {
-                "type": "string"
+            "channel_overrides": {
+                "type": "object",
+                "additionalProperties": {
+                    "$ref": "#/definitions/Partial<ChannelOverride>"
+                }
             },
-            "accent_color": {
-                "type": [
-                    "null",
-                    "integer"
-                ]
+            "version": {
+                "type": "integer"
             },
-            "banner": {
+            "guild_id": {
                 "type": [
                     "null",
                     "string"
                 ]
             },
-            "pronouns": {
-                "type": "string"
+            "flags": {
+                "type": "integer"
             },
-            "theme_colors": {
-                "type": "array",
-                "items": [
+            "message_notifications": {
+                "type": "integer"
+            },
+            "mobile_push": {
+                "type": "boolean"
+            },
+            "mute_config": {
+                "anyOf": [
                     {
-                        "type": "integer"
+                        "$ref": "#/definitions/MuteConfig"
                     },
                     {
-                        "type": "integer"
+                        "type": "null"
                     }
+                ]
+            },
+            "muted": {
+                "type": "boolean"
+            },
+            "suppress_everyone": {
+                "type": "boolean"
+            },
+            "suppress_roles": {
+                "type": "boolean"
+            },
+            "mute_scheduled_events": {
+                "type": "boolean"
+            },
+            "hide_muted_channels": {
+                "type": "boolean"
+            },
+            "notify_highlights": {
+                "enum": [
+                    0
                 ],
-                "minItems": 2,
-                "maxItems": 2
+                "type": "number"
             }
         },
         "additionalProperties": false,
@@ -23076,128 +23721,49 @@
         },
         "$schema": "http://json-schema.org/draft-07/schema#"
     },
-    "UserSettingsSchema": {
+    "UserModifySchema": {
         "type": "object",
         "properties": {
-            "afk_timeout": {
-                "type": "integer"
-            },
-            "allow_accessibility_detection": {
-                "type": "boolean"
-            },
-            "animate_emoji": {
-                "type": "boolean"
-            },
-            "animate_stickers": {
-                "type": "integer"
-            },
-            "contact_sync_enabled": {
-                "type": "boolean"
-            },
-            "convert_emoticons": {
-                "type": "boolean"
+            "username": {
+                "minLength": 1,
+                "maxLength": 100,
+                "type": "string"
             },
-            "custom_status": {
-                "anyOf": [
-                    {
-                        "$ref": "#/definitions/CustomStatus"
-                    },
-                    {
-                        "type": "null"
-                    }
+            "avatar": {
+                "type": [
+                    "null",
+                    "string"
                 ]
             },
-            "default_guilds_restricted": {
-                "type": "boolean"
-            },
-            "detect_platform_accounts": {
-                "type": "boolean"
-            },
-            "developer_mode": {
-                "type": "boolean"
-            },
-            "disable_games_tab": {
-                "type": "boolean"
-            },
-            "enable_tts_command": {
-                "type": "boolean"
+            "bio": {
+                "maxLength": 1024,
+                "type": "string"
             },
-            "explicit_content_filter": {
+            "accent_color": {
                 "type": "integer"
             },
-            "friend_source_flags": {
-                "$ref": "#/definitions/FriendSourceFlags"
-            },
-            "gateway_connected": {
-                "type": "boolean"
-            },
-            "gif_auto_play": {
-                "type": "boolean"
-            },
-            "guild_folders": {
-                "type": "array",
-                "items": {
-                    "$ref": "#/definitions/GuildFolder"
-                }
-            },
-            "guild_positions": {
-                "type": "array",
-                "items": {
-                    "type": "string"
-                }
-            },
-            "inline_attachment_media": {
-                "type": "boolean"
-            },
-            "inline_embed_media": {
-                "type": "boolean"
+            "banner": {
+                "type": [
+                    "null",
+                    "string"
+                ]
             },
-            "locale": {
+            "password": {
                 "type": "string"
             },
-            "message_display_compact": {
-                "type": "boolean"
-            },
-            "native_phone_integration_enabled": {
-                "type": "boolean"
-            },
-            "render_embeds": {
-                "type": "boolean"
-            },
-            "render_reactions": {
-                "type": "boolean"
-            },
-            "restricted_guilds": {
-                "type": "array",
-                "items": {
-                    "type": "string"
-                }
-            },
-            "show_current_game": {
-                "type": "boolean"
-            },
-            "status": {
-                "enum": [
-                    "dnd",
-                    "idle",
-                    "invisible",
-                    "offline",
-                    "online"
-                ],
+            "new_password": {
                 "type": "string"
             },
-            "stream_notifications_enabled": {
-                "type": "boolean"
+            "code": {
+                "type": "string"
             },
-            "theme": {
-                "enum": [
-                    "dark",
-                    "light"
-                ],
+            "email": {
                 "type": "string"
             },
-            "timezone_offset": {
-                "type": "integer"
+            "discriminator": {
+                "minLength": 4,
+                "maxLength": 4,
+                "type": "string"
             }
         },
         "additionalProperties": false,
@@ -23780,13 +24346,39 @@
         },
         "$schema": "http://json-schema.org/draft-07/schema#"
     },
-    "VanityUrlSchema": {
+    "UserProfileModifySchema": {
         "type": "object",
         "properties": {
-            "code": {
-                "minLength": 1,
-                "maxLength": 20,
+            "bio": {
+                "type": "string"
+            },
+            "accent_color": {
+                "type": [
+                    "null",
+                    "integer"
+                ]
+            },
+            "banner": {
+                "type": [
+                    "null",
+                    "string"
+                ]
+            },
+            "pronouns": {
                 "type": "string"
+            },
+            "theme_colors": {
+                "type": "array",
+                "items": [
+                    {
+                        "type": "integer"
+                    },
+                    {
+                        "type": "integer"
+                    }
+                ],
+                "minItems": 2,
+                "maxItems": 2
             }
         },
         "additionalProperties": false,
@@ -24369,55 +24961,131 @@
         },
         "$schema": "http://json-schema.org/draft-07/schema#"
     },
-    "VoiceIdentifySchema": {
+    "UserSettingsSchema": {
         "type": "object",
         "properties": {
-            "server_id": {
-                "type": "string"
+            "afk_timeout": {
+                "type": "integer"
             },
-            "user_id": {
-                "type": "string"
+            "allow_accessibility_detection": {
+                "type": "boolean"
             },
-            "session_id": {
-                "type": "string"
+            "animate_emoji": {
+                "type": "boolean"
             },
-            "token": {
+            "animate_stickers": {
+                "type": "integer"
+            },
+            "contact_sync_enabled": {
+                "type": "boolean"
+            },
+            "convert_emoticons": {
+                "type": "boolean"
+            },
+            "custom_status": {
+                "anyOf": [
+                    {
+                        "$ref": "#/definitions/CustomStatus"
+                    },
+                    {
+                        "type": "null"
+                    }
+                ]
+            },
+            "default_guilds_restricted": {
+                "type": "boolean"
+            },
+            "detect_platform_accounts": {
+                "type": "boolean"
+            },
+            "developer_mode": {
+                "type": "boolean"
+            },
+            "disable_games_tab": {
+                "type": "boolean"
+            },
+            "enable_tts_command": {
+                "type": "boolean"
+            },
+            "explicit_content_filter": {
+                "type": "integer"
+            },
+            "friend_source_flags": {
+                "$ref": "#/definitions/FriendSourceFlags"
+            },
+            "gateway_connected": {
+                "type": "boolean"
+            },
+            "gif_auto_play": {
+                "type": "boolean"
+            },
+            "guild_folders": {
+                "type": "array",
+                "items": {
+                    "$ref": "#/definitions/GuildFolder"
+                }
+            },
+            "guild_positions": {
+                "type": "array",
+                "items": {
+                    "type": "string"
+                }
+            },
+            "inline_attachment_media": {
+                "type": "boolean"
+            },
+            "inline_embed_media": {
+                "type": "boolean"
+            },
+            "locale": {
                 "type": "string"
             },
-            "video": {
+            "message_display_compact": {
                 "type": "boolean"
             },
-            "streams": {
+            "native_phone_integration_enabled": {
+                "type": "boolean"
+            },
+            "render_embeds": {
+                "type": "boolean"
+            },
+            "render_reactions": {
+                "type": "boolean"
+            },
+            "restricted_guilds": {
                 "type": "array",
                 "items": {
-                    "type": "object",
-                    "properties": {
-                        "type": {
-                            "type": "string"
-                        },
-                        "rid": {
-                            "type": "string"
-                        },
-                        "quality": {
-                            "type": "integer"
-                        }
-                    },
-                    "additionalProperties": false,
-                    "required": [
-                        "quality",
-                        "rid",
-                        "type"
-                    ]
+                    "type": "string"
                 }
+            },
+            "show_current_game": {
+                "type": "boolean"
+            },
+            "status": {
+                "enum": [
+                    "dnd",
+                    "idle",
+                    "invisible",
+                    "offline",
+                    "online"
+                ],
+                "type": "string"
+            },
+            "stream_notifications_enabled": {
+                "type": "boolean"
+            },
+            "theme": {
+                "enum": [
+                    "dark",
+                    "light"
+                ],
+                "type": "string"
+            },
+            "timezone_offset": {
+                "type": "integer"
             }
         },
         "additionalProperties": false,
-        "required": [
-            "server_id",
-            "session_id",
-            "token",
-            "user_id"
-        ],
         "definitions": {
             "ChannelPermissionOverwriteType": {
                 "enum": [
@@ -24997,40 +25665,16 @@
         },
         "$schema": "http://json-schema.org/draft-07/schema#"
     },
-    "VoiceStateUpdateSchema": {
+    "VanityUrlSchema": {
         "type": "object",
         "properties": {
-            "guild_id": {
-                "type": "string"
-            },
-            "channel_id": {
-                "type": "string"
-            },
-            "self_mute": {
-                "type": "boolean"
-            },
-            "self_deaf": {
-                "type": "boolean"
-            },
-            "self_video": {
-                "type": "boolean"
-            },
-            "preferred_region": {
+            "code": {
+                "minLength": 1,
+                "maxLength": 20,
                 "type": "string"
-            },
-            "request_to_speak_timestamp": {
-                "type": "string",
-                "format": "date-time"
-            },
-            "suppress": {
-                "type": "boolean"
             }
         },
         "additionalProperties": false,
-        "required": [
-            "self_deaf",
-            "self_mute"
-        ],
         "definitions": {
             "ChannelPermissionOverwriteType": {
                 "enum": [
@@ -25610,85 +26254,43 @@
         },
         "$schema": "http://json-schema.org/draft-07/schema#"
     },
-    "VoiceVideoSchema": {
+    "VoiceIdentifySchema": {
         "type": "object",
         "properties": {
-            "audio_ssrc": {
-                "type": "integer"
+            "server_id": {
+                "type": "string"
             },
-            "video_ssrc": {
-                "type": "integer"
+            "user_id": {
+                "type": "string"
             },
-            "rtx_ssrc": {
-                "type": "integer"
+            "session_id": {
+                "type": "string"
             },
-            "user_id": {
+            "token": {
                 "type": "string"
             },
+            "video": {
+                "type": "boolean"
+            },
             "streams": {
                 "type": "array",
                 "items": {
                     "type": "object",
                     "properties": {
                         "type": {
-                            "enum": [
-                                "audio",
-                                "video"
-                            ],
                             "type": "string"
                         },
                         "rid": {
                             "type": "string"
                         },
-                        "ssrc": {
-                            "type": "integer"
-                        },
-                        "active": {
-                            "type": "boolean"
-                        },
                         "quality": {
                             "type": "integer"
-                        },
-                        "rtx_ssrc": {
-                            "type": "integer"
-                        },
-                        "max_bitrate": {
-                            "type": "integer"
-                        },
-                        "max_framerate": {
-                            "type": "integer"
-                        },
-                        "max_resolution": {
-                            "type": "object",
-                            "properties": {
-                                "type": {
-                                    "type": "string"
-                                },
-                                "width": {
-                                    "type": "integer"
-                                },
-                                "height": {
-                                    "type": "integer"
-                                }
-                            },
-                            "additionalProperties": false,
-                            "required": [
-                                "height",
-                                "type",
-                                "width"
-                            ]
                         }
                     },
                     "additionalProperties": false,
                     "required": [
-                        "active",
-                        "max_bitrate",
-                        "max_framerate",
-                        "max_resolution",
                         "quality",
                         "rid",
-                        "rtx_ssrc",
-                        "ssrc",
                         "type"
                     ]
                 }
@@ -25696,8 +26298,10 @@
         },
         "additionalProperties": false,
         "required": [
-            "audio_ssrc",
-            "video_ssrc"
+            "server_id",
+            "session_id",
+            "token",
+            "user_id"
         ],
         "definitions": {
             "ChannelPermissionOverwriteType": {
@@ -26278,16 +26882,39 @@
         },
         "$schema": "http://json-schema.org/draft-07/schema#"
     },
-    "GenerateWebAuthnCredentialsSchema": {
+    "VoiceStateUpdateSchema": {
         "type": "object",
         "properties": {
-            "password": {
+            "guild_id": {
                 "type": "string"
+            },
+            "channel_id": {
+                "type": "string"
+            },
+            "self_mute": {
+                "type": "boolean"
+            },
+            "self_deaf": {
+                "type": "boolean"
+            },
+            "self_video": {
+                "type": "boolean"
+            },
+            "preferred_region": {
+                "type": "string"
+            },
+            "request_to_speak_timestamp": {
+                "type": "string",
+                "format": "date-time"
+            },
+            "suppress": {
+                "type": "boolean"
             }
         },
         "additionalProperties": false,
         "required": [
-            "password"
+            "self_deaf",
+            "self_mute"
         ],
         "definitions": {
             "ChannelPermissionOverwriteType": {
@@ -26868,24 +27495,94 @@
         },
         "$schema": "http://json-schema.org/draft-07/schema#"
     },
-    "CreateWebAuthnCredentialSchema": {
+    "VoiceVideoSchema": {
         "type": "object",
         "properties": {
-            "credential": {
-                "type": "string"
+            "audio_ssrc": {
+                "type": "integer"
             },
-            "name": {
-                "type": "string"
+            "video_ssrc": {
+                "type": "integer"
             },
-            "ticket": {
+            "rtx_ssrc": {
+                "type": "integer"
+            },
+            "user_id": {
                 "type": "string"
+            },
+            "streams": {
+                "type": "array",
+                "items": {
+                    "type": "object",
+                    "properties": {
+                        "type": {
+                            "enum": [
+                                "audio",
+                                "video"
+                            ],
+                            "type": "string"
+                        },
+                        "rid": {
+                            "type": "string"
+                        },
+                        "ssrc": {
+                            "type": "integer"
+                        },
+                        "active": {
+                            "type": "boolean"
+                        },
+                        "quality": {
+                            "type": "integer"
+                        },
+                        "rtx_ssrc": {
+                            "type": "integer"
+                        },
+                        "max_bitrate": {
+                            "type": "integer"
+                        },
+                        "max_framerate": {
+                            "type": "integer"
+                        },
+                        "max_resolution": {
+                            "type": "object",
+                            "properties": {
+                                "type": {
+                                    "type": "string"
+                                },
+                                "width": {
+                                    "type": "integer"
+                                },
+                                "height": {
+                                    "type": "integer"
+                                }
+                            },
+                            "additionalProperties": false,
+                            "required": [
+                                "height",
+                                "type",
+                                "width"
+                            ]
+                        }
+                    },
+                    "additionalProperties": false,
+                    "required": [
+                        "active",
+                        "max_bitrate",
+                        "max_framerate",
+                        "max_resolution",
+                        "quality",
+                        "rid",
+                        "rtx_ssrc",
+                        "ssrc",
+                        "type"
+                    ]
+                }
             }
         },
         "additionalProperties": false,
         "required": [
-            "credential",
-            "name",
-            "ticket"
+            "audio_ssrc",
+            "video_ssrc"
         ],
         "definitions": {
             "ChannelPermissionOverwriteType": {
@@ -27466,14 +28163,16 @@
         },
         "$schema": "http://json-schema.org/draft-07/schema#"
     },
-    "WebAuthnPostSchema": {
-        "anyOf": [
-            {
-                "$ref": "#/definitions/Partial<GenerateWebAuthnCredentialsSchema>"
-            },
-            {
-                "$ref": "#/definitions/Partial<CreateWebAuthnCredentialSchema>"
+    "GenerateWebAuthnCredentialsSchema": {
+        "type": "object",
+        "properties": {
+            "password": {
+                "type": "string"
             }
+        },
+        "additionalProperties": false,
+        "required": [
+            "password"
         ],
         "definitions": {
             "ChannelPermissionOverwriteType": {
@@ -28054,10 +28753,13 @@
         },
         "$schema": "http://json-schema.org/draft-07/schema#"
     },
-    "WebAuthnTotpSchema": {
+    "CreateWebAuthnCredentialSchema": {
         "type": "object",
         "properties": {
-            "code": {
+            "credential": {
+                "type": "string"
+            },
+            "name": {
                 "type": "string"
             },
             "ticket": {
@@ -28066,7 +28768,8 @@
         },
         "additionalProperties": false,
         "required": [
-            "code",
+            "credential",
+            "name",
             "ticket"
         ],
         "definitions": {
@@ -28648,20 +29351,14 @@
         },
         "$schema": "http://json-schema.org/draft-07/schema#"
     },
-    "WebhookCreateSchema": {
-        "type": "object",
-        "properties": {
-            "name": {
-                "maxLength": 80,
-                "type": "string"
+    "WebAuthnPostSchema": {
+        "anyOf": [
+            {
+                "$ref": "#/definitions/Partial<GenerateWebAuthnCredentialsSchema>"
             },
-            "avatar": {
-                "type": "string"
+            {
+                "$ref": "#/definitions/Partial<CreateWebAuthnCredentialSchema>"
             }
-        },
-        "additionalProperties": false,
-        "required": [
-            "name"
         ],
         "definitions": {
             "ChannelPermissionOverwriteType": {
@@ -29242,20 +29939,20 @@
         },
         "$schema": "http://json-schema.org/draft-07/schema#"
     },
-    "WidgetModifySchema": {
+    "WebAuthnTotpSchema": {
         "type": "object",
         "properties": {
-            "enabled": {
-                "type": "boolean"
+            "code": {
+                "type": "string"
             },
-            "channel_id": {
+            "ticket": {
                 "type": "string"
             }
         },
         "additionalProperties": false,
         "required": [
-            "channel_id",
-            "enabled"
+            "code",
+            "ticket"
         ],
         "definitions": {
             "ChannelPermissionOverwriteType": {
@@ -29836,125 +30533,615 @@
         },
         "$schema": "http://json-schema.org/draft-07/schema#"
     },
-    "MessageEditSchema": {
+    "WebhookCreateSchema": {
         "type": "object",
         "properties": {
-            "file": {
+            "name": {
+                "maxLength": 80,
+                "type": "string"
+            },
+            "avatar": {
+                "type": "string"
+            }
+        },
+        "additionalProperties": false,
+        "required": [
+            "name"
+        ],
+        "definitions": {
+            "ChannelPermissionOverwriteType": {
+                "enum": [
+                    0,
+                    1,
+                    2
+                ],
+                "type": "number"
+            },
+            "ChannelModifySchema": {
                 "type": "object",
                 "properties": {
-                    "filename": {
+                    "name": {
+                        "maxLength": 100,
+                        "type": "string"
+                    },
+                    "type": {
+                        "enum": [
+                            0,
+                            1,
+                            10,
+                            11,
+                            12,
+                            13,
+                            14,
+                            15,
+                            2,
+                            255,
+                            3,
+                            33,
+                            34,
+                            35,
+                            4,
+                            5,
+                            6,
+                            64,
+                            7,
+                            8,
+                            9
+                        ],
+                        "type": "number"
+                    },
+                    "topic": {
                         "type": "string"
+                    },
+                    "icon": {
+                        "type": [
+                            "null",
+                            "string"
+                        ]
+                    },
+                    "bitrate": {
+                        "type": "integer"
+                    },
+                    "user_limit": {
+                        "type": "integer"
+                    },
+                    "rate_limit_per_user": {
+                        "type": "integer"
+                    },
+                    "position": {
+                        "type": "integer"
+                    },
+                    "permission_overwrites": {
+                        "type": "array",
+                        "items": {
+                            "type": "object",
+                            "properties": {
+                                "id": {
+                                    "type": "string"
+                                },
+                                "type": {
+                                    "$ref": "#/definitions/ChannelPermissionOverwriteType"
+                                },
+                                "allow": {
+                                    "type": "string"
+                                },
+                                "deny": {
+                                    "type": "string"
+                                }
+                            },
+                            "additionalProperties": false,
+                            "required": [
+                                "allow",
+                                "deny",
+                                "id",
+                                "type"
+                            ]
+                        }
+                    },
+                    "parent_id": {
+                        "type": "string"
+                    },
+                    "id": {
+                        "type": "string"
+                    },
+                    "nsfw": {
+                        "type": "boolean"
+                    },
+                    "rtc_region": {
+                        "type": "string"
+                    },
+                    "default_auto_archive_duration": {
+                        "type": "integer"
+                    },
+                    "default_reaction_emoji": {
+                        "type": [
+                            "null",
+                            "string"
+                        ]
+                    },
+                    "flags": {
+                        "type": "integer"
+                    },
+                    "default_thread_rate_limit_per_user": {
+                        "type": "integer"
+                    },
+                    "video_quality_mode": {
+                        "type": "integer"
+                    }
+                },
+                "additionalProperties": false
+            },
+            "ActivitySchema": {
+                "type": "object",
+                "properties": {
+                    "afk": {
+                        "type": "boolean"
+                    },
+                    "status": {
+                        "$ref": "#/definitions/Status"
+                    },
+                    "activities": {
+                        "type": "array",
+                        "items": {
+                            "$ref": "#/definitions/Activity"
+                        }
+                    },
+                    "since": {
+                        "type": "integer"
                     }
                 },
                 "additionalProperties": false,
                 "required": [
-                    "filename"
+                    "status"
                 ]
             },
-            "embed": {
-                "$ref": "#/definitions/Embed"
-            },
-            "flags": {
-                "type": "string"
-            },
-            "content": {
-                "type": "string"
-            },
-            "nonce": {
+            "Status": {
+                "enum": [
+                    "dnd",
+                    "idle",
+                    "invisible",
+                    "offline",
+                    "online"
+                ],
                 "type": "string"
             },
-            "channel_id": {
-                "type": "string"
+            "Activity": {
+                "type": "object",
+                "properties": {
+                    "name": {
+                        "type": "string"
+                    },
+                    "type": {
+                        "$ref": "#/definitions/ActivityType"
+                    },
+                    "url": {
+                        "type": "string"
+                    },
+                    "created_at": {
+                        "type": "integer"
+                    },
+                    "timestamps": {
+                        "type": "object",
+                        "properties": {
+                            "start": {
+                                "type": "integer"
+                            },
+                            "end": {
+                                "type": "integer"
+                            }
+                        },
+                        "additionalProperties": false,
+                        "required": [
+                            "end",
+                            "start"
+                        ]
+                    },
+                    "application_id": {
+                        "type": "string"
+                    },
+                    "details": {
+                        "type": "string"
+                    },
+                    "state": {
+                        "type": "string"
+                    },
+                    "emoji": {
+                        "type": "object",
+                        "properties": {
+                            "name": {
+                                "type": "string"
+                            },
+                            "id": {
+                                "type": "string"
+                            },
+                            "animated": {
+                                "type": "boolean"
+                            }
+                        },
+                        "additionalProperties": false,
+                        "required": [
+                            "animated",
+                            "name"
+                        ]
+                    },
+                    "party": {
+                        "type": "object",
+                        "properties": {
+                            "id": {
+                                "type": "string"
+                            },
+                            "size": {
+                                "type": "array",
+                                "items": [
+                                    {
+                                        "type": "integer"
+                                    }
+                                ],
+                                "minItems": 1,
+                                "maxItems": 1
+                            }
+                        },
+                        "additionalProperties": false
+                    },
+                    "assets": {
+                        "type": "object",
+                        "properties": {
+                            "large_image": {
+                                "type": "string"
+                            },
+                            "large_text": {
+                                "type": "string"
+                            },
+                            "small_image": {
+                                "type": "string"
+                            },
+                            "small_text": {
+                                "type": "string"
+                            }
+                        },
+                        "additionalProperties": false
+                    },
+                    "secrets": {
+                        "type": "object",
+                        "properties": {
+                            "join": {
+                                "type": "string"
+                            },
+                            "spectate": {
+                                "type": "string"
+                            },
+                            "match": {
+                                "type": "string"
+                            }
+                        },
+                        "additionalProperties": false
+                    },
+                    "instance": {
+                        "type": "boolean"
+                    },
+                    "flags": {
+                        "type": "string"
+                    },
+                    "id": {
+                        "type": "string"
+                    },
+                    "sync_id": {
+                        "type": "string"
+                    },
+                    "metadata": {
+                        "type": "object",
+                        "properties": {
+                            "context_uri": {
+                                "type": "string"
+                            },
+                            "album_id": {
+                                "type": "string"
+                            },
+                            "artist_ids": {
+                                "type": "array",
+                                "items": {
+                                    "type": "string"
+                                }
+                            }
+                        },
+                        "additionalProperties": false,
+                        "required": [
+                            "album_id",
+                            "artist_ids"
+                        ]
+                    },
+                    "session_id": {
+                        "type": "string"
+                    }
+                },
+                "additionalProperties": false,
+                "required": [
+                    "flags",
+                    "name",
+                    "session_id",
+                    "type"
+                ]
             },
-            "tts": {
-                "type": "boolean"
+            "ActivityType": {
+                "enum": [
+                    0,
+                    1,
+                    2,
+                    4,
+                    5
+                ],
+                "type": "number"
             },
-            "embeds": {
-                "type": "array",
-                "items": {
-                    "$ref": "#/definitions/Embed"
-                }
+            "Record<string,[number,number][]>": {
+                "type": "object",
+                "additionalProperties": false
             },
-            "allowed_mentions": {
+            "Embed": {
                 "type": "object",
                 "properties": {
-                    "parse": {
-                        "type": "array",
-                        "items": {
-                            "type": "string"
-                        }
+                    "title": {
+                        "type": "string"
                     },
-                    "roles": {
-                        "type": "array",
-                        "items": {
-                            "type": "string"
-                        }
+                    "type": {
+                        "enum": [
+                            "article",
+                            "gifv",
+                            "image",
+                            "link",
+                            "rich",
+                            "video"
+                        ],
+                        "type": "string"
                     },
-                    "users": {
+                    "description": {
+                        "type": "string"
+                    },
+                    "url": {
+                        "type": "string"
+                    },
+                    "timestamp": {
+                        "type": "string",
+                        "format": "date-time"
+                    },
+                    "color": {
+                        "type": "integer"
+                    },
+                    "footer": {
+                        "type": "object",
+                        "properties": {
+                            "text": {
+                                "type": "string"
+                            },
+                            "icon_url": {
+                                "type": "string"
+                            },
+                            "proxy_icon_url": {
+                                "type": "string"
+                            }
+                        },
+                        "additionalProperties": false,
+                        "required": [
+                            "text"
+                        ]
+                    },
+                    "image": {
+                        "$ref": "#/definitions/EmbedImage"
+                    },
+                    "thumbnail": {
+                        "$ref": "#/definitions/EmbedImage"
+                    },
+                    "video": {
+                        "$ref": "#/definitions/EmbedImage"
+                    },
+                    "provider": {
+                        "type": "object",
+                        "properties": {
+                            "name": {
+                                "type": "string"
+                            },
+                            "url": {
+                                "type": "string"
+                            }
+                        },
+                        "additionalProperties": false
+                    },
+                    "author": {
+                        "type": "object",
+                        "properties": {
+                            "name": {
+                                "type": "string"
+                            },
+                            "url": {
+                                "type": "string"
+                            },
+                            "icon_url": {
+                                "type": "string"
+                            },
+                            "proxy_icon_url": {
+                                "type": "string"
+                            }
+                        },
+                        "additionalProperties": false
+                    },
+                    "fields": {
                         "type": "array",
                         "items": {
-                            "type": "string"
+                            "type": "object",
+                            "properties": {
+                                "name": {
+                                    "type": "string"
+                                },
+                                "value": {
+                                    "type": "string"
+                                },
+                                "inline": {
+                                    "type": "boolean"
+                                }
+                            },
+                            "additionalProperties": false,
+                            "required": [
+                                "name",
+                                "value"
+                            ]
                         }
-                    },
-                    "replied_user": {
-                        "type": "boolean"
                     }
                 },
                 "additionalProperties": false
             },
-            "message_reference": {
+            "EmbedImage": {
                 "type": "object",
                 "properties": {
-                    "message_id": {
+                    "url": {
                         "type": "string"
                     },
+                    "proxy_url": {
+                        "type": "string"
+                    },
+                    "height": {
+                        "type": "integer"
+                    },
+                    "width": {
+                        "type": "integer"
+                    }
+                },
+                "additionalProperties": false
+            },
+            "Partial<ChannelOverride>": {
+                "type": "object",
+                "properties": {
+                    "message_notifications": {
+                        "type": "integer"
+                    },
+                    "mute_config": {
+                        "$ref": "#/definitions/MuteConfig"
+                    },
+                    "muted": {
+                        "type": "boolean"
+                    },
                     "channel_id": {
+                        "type": [
+                            "null",
+                            "string"
+                        ]
+                    }
+                },
+                "additionalProperties": false
+            },
+            "MuteConfig": {
+                "type": "object",
+                "properties": {
+                    "end_time": {
+                        "type": "integer"
+                    },
+                    "selected_time_window": {
+                        "type": "integer"
+                    }
+                },
+                "additionalProperties": false,
+                "required": [
+                    "end_time",
+                    "selected_time_window"
+                ]
+            },
+            "CustomStatus": {
+                "type": "object",
+                "properties": {
+                    "emoji_id": {
                         "type": "string"
                     },
-                    "guild_id": {
+                    "emoji_name": {
                         "type": "string"
                     },
-                    "fail_if_not_exists": {
+                    "expires_at": {
+                        "type": "integer"
+                    },
+                    "text": {
+                        "type": "string"
+                    }
+                },
+                "additionalProperties": false
+            },
+            "FriendSourceFlags": {
+                "type": "object",
+                "properties": {
+                    "all": {
                         "type": "boolean"
                     }
                 },
                 "additionalProperties": false,
                 "required": [
-                    "channel_id",
-                    "message_id"
+                    "all"
                 ]
             },
-            "payload_json": {
-                "type": "string"
-            },
-            "attachments": {
-                "description": "TODO: we should create an interface for attachments\nTODO: OpenWAAO<-->attachment-style metadata conversion",
-                "type": "array",
-                "items": {
-                    "type": "object",
-                    "properties": {
-                        "id": {
-                            "type": "string"
-                        },
-                        "filename": {
+            "GuildFolder": {
+                "type": "object",
+                "properties": {
+                    "color": {
+                        "type": "integer"
+                    },
+                    "guild_ids": {
+                        "type": "array",
+                        "items": {
                             "type": "string"
                         }
                     },
-                    "additionalProperties": false,
-                    "required": [
-                        "filename",
-                        "id"
-                    ]
-                }
+                    "id": {
+                        "type": "integer"
+                    },
+                    "name": {
+                        "type": "string"
+                    }
+                },
+                "additionalProperties": false,
+                "required": [
+                    "color",
+                    "guild_ids",
+                    "id",
+                    "name"
+                ]
             },
-            "sticker_ids": {
-                "type": "array",
-                "items": {
-                    "type": "string"
-                }
+            "Partial<GenerateWebAuthnCredentialsSchema>": {
+                "type": "object",
+                "properties": {
+                    "password": {
+                        "type": "string"
+                    }
+                },
+                "additionalProperties": false
+            },
+            "Partial<CreateWebAuthnCredentialSchema>": {
+                "type": "object",
+                "properties": {
+                    "credential": {
+                        "type": "string"
+                    },
+                    "name": {
+                        "type": "string"
+                    },
+                    "ticket": {
+                        "type": "string"
+                    }
+                },
+                "additionalProperties": false
+            }
+        },
+        "$schema": "http://json-schema.org/draft-07/schema#"
+    },
+    "WidgetModifySchema": {
+        "type": "object",
+        "properties": {
+            "enabled": {
+                "type": "boolean"
+            },
+            "channel_id": {
+                "type": "string"
             }
         },
         "additionalProperties": false,
+        "required": [
+            "channel_id",
+            "enabled"
+        ],
         "definitions": {
             "ChannelPermissionOverwriteType": {
                 "enum": [
diff --git a/src/api/middlewares/Authentication.ts b/src/api/middlewares/Authentication.ts
index f4c33963..771f0de8 100644
--- a/src/api/middlewares/Authentication.ts
+++ b/src/api/middlewares/Authentication.ts
@@ -29,6 +29,8 @@ export const NO_AUTHORIZATION_ROUTES = [
 	"/auth/mfa/totp",
 	"/auth/mfa/webauthn",
 	"/auth/verify",
+	"/auth/forgot",
+	"/auth/reset",
 	// Routes with a seperate auth system
 	"/webhooks/",
 	// Public information endpoints
diff --git a/src/api/routes/auth/forgot.ts b/src/api/routes/auth/forgot.ts
new file mode 100644
index 00000000..faa43dbb
--- /dev/null
+++ b/src/api/routes/auth/forgot.ts
@@ -0,0 +1,92 @@
+import { getIpAdress, route, verifyCaptcha } from "@fosscord/api";
+import {
+	Config,
+	Email,
+	FieldErrors,
+	ForgotPasswordSchema,
+	User,
+} from "@fosscord/util";
+import { Request, Response, Router } from "express";
+import { HTTPError } from "lambert-server";
+const router = Router();
+
+router.post(
+	"/",
+	route({ body: "ForgotPasswordSchema" }),
+	async (req: Request, res: Response) => {
+		const { login, captcha_key } = req.body as ForgotPasswordSchema;
+
+		const config = Config.get();
+
+		if (
+			config.password_reset.requireCaptcha &&
+			config.security.captcha.enabled
+		) {
+			const { sitekey, service } = config.security.captcha;
+			if (!captcha_key) {
+				return res.status(400).json({
+					captcha_key: ["captcha-required"],
+					captcha_sitekey: sitekey,
+					captcha_service: service,
+				});
+			}
+
+			const ip = getIpAdress(req);
+			const verify = await verifyCaptcha(captcha_key, ip);
+			if (!verify.success) {
+				return res.status(400).json({
+					captcha_key: verify["error-codes"],
+					captcha_sitekey: sitekey,
+					captcha_service: service,
+				});
+			}
+		}
+
+		const user = await User.findOneOrFail({
+			where: [{ phone: login }, { email: login }],
+			select: ["username", "id", "disabled", "deleted", "email"],
+			relations: ["security_keys"],
+		}).catch(() => {
+			throw FieldErrors({
+				login: {
+					message: req.t("auth:password_reset.EMAIL_DOES_NOT_EXIST"),
+					code: "EMAIL_DOES_NOT_EXIST",
+				},
+			});
+		});
+
+		if (!user.email)
+			throw FieldErrors({
+				login: {
+					message:
+						"This account does not have an email address associated with it.",
+					code: "NO_EMAIL",
+				},
+			});
+
+		if (user.deleted)
+			return res.status(400).json({
+				message: "This account is scheduled for deletion.",
+				code: 20011,
+			});
+
+		if (user.disabled)
+			return res.status(400).json({
+				message: req.t("auth:login.ACCOUNT_DISABLED"),
+				code: 20013,
+			});
+
+		return await Email.sendResetPassword(user, user.email)
+			.then(() => {
+				return res.sendStatus(204);
+			})
+			.catch((e) => {
+				console.error(
+					`Failed to send password reset email to ${user.username}#${user.discriminator}: ${e}`,
+				);
+				throw new HTTPError("Failed to send password reset email", 500);
+			});
+	},
+);
+
+export default router;
diff --git a/src/api/routes/auth/reset.ts b/src/api/routes/auth/reset.ts
new file mode 100644
index 00000000..94053e1a
--- /dev/null
+++ b/src/api/routes/auth/reset.ts
@@ -0,0 +1,57 @@
+import { route } from "@fosscord/api";
+import {
+	checkToken,
+	Config,
+	Email,
+	FieldErrors,
+	generateToken,
+	PasswordResetSchema,
+	User,
+} from "@fosscord/util";
+import bcrypt from "bcrypt";
+import { Request, Response, Router } from "express";
+import { HTTPError } from "lambert-server";
+
+const router = Router();
+
+router.post(
+	"/",
+	route({ body: "PasswordResetSchema" }),
+	async (req: Request, res: Response) => {
+		const { password, token } = req.body as PasswordResetSchema;
+
+		try {
+			const { jwtSecret } = Config.get().security;
+			const { user } = await checkToken(token, jwtSecret, true);
+
+			// the salt is saved in the password refer to bcrypt docs
+			const hash = await bcrypt.hash(password, 12);
+
+			const data = {
+				data: {
+					hash,
+					valid_tokens_since: new Date(),
+				},
+			};
+			await User.update({ id: user.id }, data);
+
+			// come on, the user has to have an email to reset their password in the first place
+			// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+			await Email.sendPasswordChanged(user, user.email!);
+
+			res.json({ token: await generateToken(user.id) });
+		} catch (e) {
+			if ((e as Error).toString() === "Invalid Token")
+				throw FieldErrors({
+					password: {
+						message: req.t("auth:password_reset.INVALID_TOKEN"),
+						code: "INVALID_TOKEN",
+					},
+				});
+
+			throw new HTTPError((e as Error).toString(), 400);
+		}
+	},
+);
+
+export default router;
diff --git a/src/api/routes/auth/verify/resend.ts b/src/api/routes/auth/verify/resend.ts
index 1cd14f23..918af9a1 100644
--- a/src/api/routes/auth/verify/resend.ts
+++ b/src/api/routes/auth/verify/resend.ts
@@ -36,7 +36,7 @@ router.post(
 			throw new HTTPError("User does not have an email address", 400);
 		}
 
-		await Email.sendVerificationEmail(user, user.email)
+		await Email.sendVerifyEmail(user, user.email)
 			.then(() => {
 				return res.sendStatus(204);
 			})
diff --git a/src/util/config/Config.ts b/src/util/config/Config.ts
index d6f804bf..c056d454 100644
--- a/src/util/config/Config.ts
+++ b/src/util/config/Config.ts
@@ -31,6 +31,7 @@ import {
 	LimitsConfiguration,
 	LoginConfiguration,
 	MetricsConfiguration,
+	PasswordResetConfiguration,
 	RabbitMQConfiguration,
 	RegionConfiguration,
 	RegisterConfiguration,
@@ -60,4 +61,6 @@ export class ConfigValue {
 	defaults: DefaultsConfiguration = new DefaultsConfiguration();
 	external: ExternalTokensConfiguration = new ExternalTokensConfiguration();
 	email: EmailConfiguration = new EmailConfiguration();
+	password_reset: PasswordResetConfiguration =
+		new PasswordResetConfiguration();
 }
diff --git a/src/util/config/types/PasswordResetConfiguration.ts b/src/util/config/types/PasswordResetConfiguration.ts
new file mode 100644
index 00000000..806d77be
--- /dev/null
+++ b/src/util/config/types/PasswordResetConfiguration.ts
@@ -0,0 +1,21 @@
+/*
+	Fosscord: A FOSS re-implementation and extension of the Discord.com backend.
+	Copyright (C) 2023 Fosscord and Fosscord Contributors
+	
+	This program is free software: you can redistribute it and/or modify
+	it under the terms of the GNU Affero General Public License as published
+	by the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
+	
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU Affero General Public License for more details.
+	
+	You should have received a copy of the GNU Affero General Public License
+	along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+
+export class PasswordResetConfiguration {
+	requireCaptcha: boolean = false;
+}
diff --git a/src/util/config/types/index.ts b/src/util/config/types/index.ts
index 1431c128..510e19f8 100644
--- a/src/util/config/types/index.ts
+++ b/src/util/config/types/index.ts
@@ -30,6 +30,7 @@ export * from "./KafkaConfiguration";
 export * from "./LimitConfigurations";
 export * from "./LoginConfiguration";
 export * from "./MetricsConfiguration";
+export * from "./PasswordResetConfiguration";
 export * from "./RabbitMQConfiguration";
 export * from "./RegionConfiguration";
 export * from "./RegisterConfiguration";
diff --git a/src/util/entities/User.ts b/src/util/entities/User.ts
index 2947b205..f99a85e7 100644
--- a/src/util/entities/User.ts
+++ b/src/util/entities/User.ts
@@ -393,7 +393,7 @@ export class User extends BaseClass {
 
 		// send verification email if users aren't verified by default and we have an email
 		if (!Config.get().defaults.user.verified && email) {
-			await Email.sendVerificationEmail(user, email).catch((e) => {
+			await Email.sendVerifyEmail(user, email).catch((e) => {
 				console.error(
 					`Failed to send verification email to ${user.username}#${user.discriminator}: ${e}`,
 				);
diff --git a/src/util/schemas/ForgotPasswordSchema.ts b/src/util/schemas/ForgotPasswordSchema.ts
new file mode 100644
index 00000000..9a28bd18
--- /dev/null
+++ b/src/util/schemas/ForgotPasswordSchema.ts
@@ -0,0 +1,22 @@
+/*
+	Fosscord: A FOSS re-implementation and extension of the Discord.com backend.
+	Copyright (C) 2023 Fosscord and Fosscord Contributors
+	
+	This program is free software: you can redistribute it and/or modify
+	it under the terms of the GNU Affero General Public License as published
+	by the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
+	
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU Affero General Public License for more details.
+	
+	You should have received a copy of the GNU Affero General Public License
+	along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+
+export interface ForgotPasswordSchema {
+	login: string;
+	captcha_key?: string;
+}
diff --git a/src/util/schemas/PasswordResetSchema.ts b/src/util/schemas/PasswordResetSchema.ts
new file mode 100644
index 00000000..9cc74940
--- /dev/null
+++ b/src/util/schemas/PasswordResetSchema.ts
@@ -0,0 +1,22 @@
+/*
+	Fosscord: A FOSS re-implementation and extension of the Discord.com backend.
+	Copyright (C) 2023 Fosscord and Fosscord Contributors
+	
+	This program is free software: you can redistribute it and/or modify
+	it under the terms of the GNU Affero General Public License as published
+	by the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
+	
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU Affero General Public License for more details.
+	
+	You should have received a copy of the GNU Affero General Public License
+	along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+
+export interface PasswordResetSchema {
+	password: string;
+	token: string;
+}
diff --git a/src/util/schemas/index.ts b/src/util/schemas/index.ts
index 194d8571..44909a3a 100644
--- a/src/util/schemas/index.ts
+++ b/src/util/schemas/index.ts
@@ -16,6 +16,7 @@
 	along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 
+export * from "./AckBulkSchema";
 export * from "./ActivitySchema";
 export * from "./ApplicationAuthorizeSchema";
 export * from "./ApplicationCreateSchema";
@@ -32,6 +33,7 @@ export * from "./CodesVerificationSchema";
 export * from "./DmChannelCreateSchema";
 export * from "./EmojiCreateSchema";
 export * from "./EmojiModifySchema";
+export * from "./ForgotPasswordSchema";
 export * from "./GatewayPayloadSchema";
 export * from "./GuildCreateSchema";
 export * from "./GuildTemplateCreateSchema";
@@ -45,8 +47,10 @@ export * from "./MemberChangeProfileSchema";
 export * from "./MemberChangeSchema";
 export * from "./MessageAcknowledgeSchema";
 export * from "./MessageCreateSchema";
+export * from "./MessageEditSchema";
 export * from "./MfaCodesSchema";
 export * from "./ModifyGuildStickerSchema";
+export * from "./PasswordResetSchema";
 export * from "./PurgeSchema";
 export * from "./RegisterSchema";
 export * from "./RelationshipPostSchema";
@@ -69,22 +73,6 @@ export * from "./VanityUrlSchema";
 export * from "./VoiceIdentifySchema";
 export * from "./VoiceStateUpdateSchema";
 export * from "./VoiceVideoSchema";
-export * from "./IdentifySchema";
-export * from "./ActivitySchema";
-export * from "./LazyRequestSchema";
-export * from "./GuildUpdateSchema";
-export * from "./ChannelPermissionOverwriteSchema";
-export * from "./UserGuildSettingsSchema";
-export * from "./GatewayPayloadSchema";
-export * from "./RolePositionUpdateSchema";
-export * from "./ChannelReorderSchema";
-export * from "./UserSettingsSchema";
-export * from "./BotModifySchema";
-export * from "./ApplicationModifySchema";
-export * from "./ApplicationCreateSchema";
-export * from "./ApplicationAuthorizeSchema";
-export * from "./AckBulkSchema";
 export * from "./WebAuthnSchema";
 export * from "./WebhookCreateSchema";
 export * from "./WidgetModifySchema";
-export * from "./MessageEditSchema";
diff --git a/src/util/util/Email.ts b/src/util/util/Email.ts
index 3028b063..fa72d9c0 100644
--- a/src/util/util/Email.ts
+++ b/src/util/util/Email.ts
@@ -194,8 +194,14 @@ const transporters = {
 export const Email: {
 	transporter: Transporter | null;
 	init: () => Promise<void>;
-	generateVerificationLink: (id: string, email: string) => Promise<string>;
-	sendVerificationEmail: (
+	generateLink: (
+		type: "verify" | "reset",
+		id: string,
+		email: string,
+	) => Promise<string>;
+	sendVerifyEmail: (user: User, email: string) => Promise<SentMessageInfo>;
+	sendResetPassword: (user: User, email: string) => Promise<SentMessageInfo>;
+	sendPasswordChanged: (
 		user: User,
 		email: string,
 	) => Promise<SentMessageInfo>;
@@ -231,10 +237,10 @@ export const Email: {
 	 * Replaces all placeholders in an email template with the correct values
 	 */
 	doReplacements: function (
-		template: string,
-		user: User,
-		emailVerificationUrl?: string,
-		passwordResetUrl?: string,
+		template,
+		user,
+		emailVerificationUrl?,
+		passwordResetUrl?,
 		ipInfo?: {
 			ip: string;
 			city: string;
@@ -285,23 +291,22 @@ export const Email: {
 	 *
 	 * @param id user id
 	 * @param email user email
-	 * @returns a verification link for the user
 	 */
-	generateVerificationLink: async function (id: string, email: string) {
+	generateLink: async function (type, id, email) {
 		const token = (await generateToken(id, email)) as string;
 		const instanceUrl =
 			Config.get().general.frontPage || "http://localhost:3001";
-		const link = `${instanceUrl}/verify#token=${token}`;
+		const link = `${instanceUrl}/${type}#token=${token}`;
 		return link;
 	},
-	sendVerificationEmail: async function (user: User, email: string) {
+	/**
+	 * Sends an email to the user with a link to verify their email address
+	 */
+	sendVerifyEmail: async function (user, email) {
 		if (!this.transporter) return;
 
 		// generate a verification link for the user
-		const verificationLink = await this.generateVerificationLink(
-			user.id,
-			email,
-		);
+		const link = await this.generateLink("verify", user.id, email);
 
 		// load the email template
 		const rawTemplate = fs.readFileSync(
@@ -314,7 +319,78 @@ export const Email: {
 		);
 
 		// replace email template placeholders
-		const html = this.doReplacements(rawTemplate, user, verificationLink);
+		const html = this.doReplacements(rawTemplate, user, link);
+
+		// extract the title from the email template to use as the email subject
+		const subject = html.match(/<title>(.*)<\/title>/)?.[1] || "";
+
+		// construct the email
+		const message = {
+			from:
+				Config.get().general.correspondenceEmail || "noreply@localhost",
+			to: email,
+			subject,
+			html,
+		};
+
+		// send the email
+		return this.transporter.sendMail(message);
+	},
+	/**
+	 * Sends an email to the user with a link to reset their password
+	 */
+	sendResetPassword: async function (user, email) {
+		if (!this.transporter) return;
+
+		// generate a password reset link for the user
+		const link = await this.generateLink("reset", user.id, email);
+
+		// load the email template
+		const rawTemplate = fs.readFileSync(
+			path.join(
+				ASSET_FOLDER_PATH,
+				"email_templates",
+				"password_reset_request.html",
+			),
+			{ encoding: "utf-8" },
+		);
+
+		// replace email template placeholders
+		const html = this.doReplacements(rawTemplate, user, undefined, link);
+
+		// extract the title from the email template to use as the email subject
+		const subject = html.match(/<title>(.*)<\/title>/)?.[1] || "";
+
+		// construct the email
+		const message = {
+			from:
+				Config.get().general.correspondenceEmail || "noreply@localhost",
+			to: email,
+			subject,
+			html,
+		};
+
+		// send the email
+		return this.transporter.sendMail(message);
+	},
+	/**
+	 * Sends an email to the user notifying them that their password has been changed
+	 */
+	sendPasswordChanged: async function (user, email) {
+		if (!this.transporter) return;
+
+		// load the email template
+		const rawTemplate = fs.readFileSync(
+			path.join(
+				ASSET_FOLDER_PATH,
+				"email_templates",
+				"password_changed.html",
+			),
+			{ encoding: "utf-8" },
+		);
+
+		// replace email template placeholders
+		const html = this.doReplacements(rawTemplate, user);
 
 		// extract the title from the email template to use as the email subject
 		const subject = html.match(/<title>(.*)<\/title>/)?.[1] || "";
diff --git a/src/util/util/Token.ts b/src/util/util/Token.ts
index e7b2006d..ffc442aa 100644
--- a/src/util/util/Token.ts
+++ b/src/util/util/Token.ts
@@ -38,6 +38,15 @@ async function checkEmailToken(
 			where: {
 				email: decoded.email,
 			},
+			select: [
+				"email",
+				"id",
+				"verified",
+				"deleted",
+				"disabled",
+				"username",
+				"data",
+			],
 		});
 
 		if (!user) return rej("Invalid Token");