{"record":{"id":"95dcf65d41d3ae56","repo":"toeverything/AFFiNE","slug":"sign-up-forbidden","errorCode":"sign_up_forbidden","errorMessage":"You are not allowed to sign up.","messagePattern":"You are not allowed to sign up\\.","errorType":"exception","errorClass":"SignUpForbidden","httpStatus":403,"severity":"error","filePath":"packages/backend/server/src/core/auth/magic-link.ts","lineNumber":135,"sourceCode":"      TokenType.SignIn,\n      consumed.token,\n      {\n        credential: email,\n      }\n    );\n\n    if (!tokenRecord) {\n      throw new InvalidEmailToken();\n    }\n\n    const user = await this.models.user.fulfill(email);\n\n    return { userId: user.id, method: 'magic_link' };\n  }\n\n  private async assertSignupAllowed(email: string) {\n    if (!this.config.auth.allowSignup) {\n      throw new SignUpForbidden();\n    }\n\n    if (!this.config.auth.requireEmailDomainVerification) {\n      return;\n    }\n\n    if (!(await verifyEmailDomainRecords(email))) {\n      throw new InvalidEmail({ email });\n    }\n  }\n}\n","sourceCodeStart":117,"sourceCodeEnd":147,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/26c515e050211269e911f7d9cfe162a26c83ed98/packages/backend/server/src/core/auth/magic-link.ts#L117-L147","documentation":"In assertSignupAllowed (reached from send when no existing user matches the email), if config.auth.allowSignup is false the server throws SignUpForbidden. This is the global signup toggle: when off, brand-new emails cannot initiate a magic-link sign-in because account creation is disabled. Existing users are unaffected (they never reach this branch).","triggerScenarios":"config.auth.allowSignup === false AND the email has no user row AND send() is called. Typical of self-hosted deployments that disable open registration.","commonSituations":"Self-hosted admin set AFFiNE_AUTH_ALLOW_SIGNUP=false (or omitted enabling it). A private deployment where accounts are provisioned out-of-band. Someone tries to self-register on an invite-only instance.","solutions":["Set config.auth.allowSignup=true (AFFiNE_AUTH_ALLOW_SIGNUP=true) and redeploy if self-registration is desired.","Provision the user account through admin tooling / invitation instead of self-signup.","Sign in with an existing account rather than attempting to register a new email.","Confirm the email is not typo'd — an existing user with a slightly different email won't match."],"exampleFix":"# enable self-signup\nAFFiNE_AUTH_ALLOW_SIGNUP=true","handlingStrategy":"validation","validationCode":null,"typeGuard":"function isSignUpForbidden(err: unknown): boolean {\n  return (\n    !!err &&\n    typeof err === 'object' &&\n    (err as { code?: string }).code === 'sign_up_forbidden'\n  );\n}","tryCatchPattern":"try {\n  await magicLink.send(email);\n} catch (err) {\n  if (isSignUpForbidden(err)) {\n    showUser('Sign-up is disabled. Contact your administrator.');\n    return;\n  }\n  throw err;\n}","preventionTips":["Gate the sign-up UI on whether allowSignup is enabled (expose via a capabilities endpoint).","On self-hosted, set AFFiNE_AUTH_ALLOW_SIGNUP explicitly to the desired value.","Provision accounts via admin invitation when allowSignup is off.","Tell users to use an existing account when registration is closed."],"tags":["auth","signup","config","registration","self-hosted"],"backgroundTag":null,"analyzedSha":"26c515e050211269e911f7d9cfe162a26c83ed98","analyzedAt":"2026-08-12T13:15:16.447Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}