Skip to content

Typescript error in auth export #5637

@satish-buildin2

Description

@satish-buildin2

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

after updating to the latest version of better auth ie "better-auth": "^1.3.33", i am facing type error in the auth export which was not before.
export const auth = betterAuth({
...
i also type caste into
export const auth: Auth = betterAuth({
...
alos tried type infer of betterAuth but didn't work.

Current vs. Expected behavior

current:
auth word shows red type error
expected:
no type error

What version of Better Auth are you using?

^1.3.33

System info

{
  "system": {
    "platform": "linux",
    "arch": "x64",
    "version": "#33~24.04.1-Ubuntu SMP PREEMPT_DYNAMIC Fri Sep 19 17:02:30 UTC 2",
    "release": "6.14.0-33-generic",
    "cpuCount": 16,
    "cpuModel": "12th Gen Intel(R) Core(TM) i5-1240P",
    "totalMemory": "15.25 GB",
    "freeMemory": "4.68 GB"
  },
  "node": {
    "version": "v22.17.1",
    "env": "development"
  },
  "packageManager": {
    "name": "npm",
    "version": "11.5.2"
  },
  "frameworks": [
    {
      "name": "express",
      "version": "^5.1.0"
    }
  ],
  "databases": null,
  "betterAuth": {
    "version": "^1.3.33",
    "config": {
      "secret": "[REDACTED]",
      "baseURL": "http://localhost:3000",
      "trustedOrigins": [
        "http://localhost:5173"
      ],
      "errorURL": "http://localhost:5173",
      "user": {
        "additionalFields": {
          "isOnboardingComplete": {
            "type": "boolean",
            "defaultValue": false,
            "required": false
          },
          "timezone": {
            "type": "string",
            "defaultValue": "Europe/London",
            "required": false
          }
        }
      },
      "account": {
        "accountLinking": {
          "enabled": true,
          "allowDifferentEmails": false,
          "updateUserInfoOnLink": true
        }
      },
      "plugins": [
        {
          "name": "admin",
          "config": {
            "id": "admin",
            "hooks": {
              "after": [
                {}
              ]
            },
            "endpoints": {},
            "$ERROR_CODES": {
              "FAILED_TO_CREATE_USER": "Failed to create user",
              "USER_ALREADY_EXISTS": "User already exists.",
              "USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL": "User already exists. Use another email.",
              "YOU_CANNOT_BAN_YOURSELF": "You cannot ban yourself",
              "YOU_ARE_NOT_ALLOWED_TO_CHANGE_USERS_ROLE": "You are not allowed to change users role",
              "YOU_ARE_NOT_ALLOWED_TO_CREATE_USERS": "You are not allowed to create users",
              "YOU_ARE_NOT_ALLOWED_TO_LIST_USERS": "You are not allowed to list users",
              "YOU_ARE_NOT_ALLOWED_TO_LIST_USERS_SESSIONS": "You are not allowed to list users sessions",
              "YOU_ARE_NOT_ALLOWED_TO_BAN_USERS": "You are not allowed to ban users",
              "YOU_ARE_NOT_ALLOWED_TO_IMPERSONATE_USERS": "You are not allowed to impersonate users",
              "YOU_ARE_NOT_ALLOWED_TO_REVOKE_USERS_SESSIONS": "You are not allowed to revoke users sessions",
              "YOU_ARE_NOT_ALLOWED_TO_DELETE_USERS": "You are not allowed to delete users",
              "YOU_ARE_NOT_ALLOWED_TO_SET_USERS_PASSWORD": "[REDACTED]",
              "BANNED_USER": "You have been banned from this application",
              "YOU_ARE_NOT_ALLOWED_TO_GET_USER": "You are not allowed to get user",
              "NO_DATA_TO_UPDATE": "No data to update",
              "YOU_ARE_NOT_ALLOWED_TO_UPDATE_USERS": "You are not allowed to update users",
              "YOU_CANNOT_REMOVE_YOURSELF": "You cannot remove yourself",
              "YOU_ARE_NOT_ALLOWED_TO_SET_NON_EXISTENT_VALUE": "You are not allowed to set a non-existent role value"
            },
            "schema": {
              "user": {
                "fields": {
                  "role": {
                    "type": "string",
                    "required": false,
                    "input": false
                  },
                  "banned": {
                    "type": "boolean",
                    "defaultValue": false,
                    "required": false,
                    "input": false
                  },
                  "banReason": {
                    "type": "string",
                    "required": false,
                    "input": false
                  },
                  "banExpires": {
                    "type": "date",
                    "required": false,
                    "input": false
                  }
                }
              },
              "session": {
                "fields": {
                  "impersonatedBy": {
                    "type": "string",
                    "required": false
                  }
                }
              }
            },
            "options": {
              "defaultRole": "user",
              "adminRoles": [
                "admin"
              ]
            }
          }
        },
        {
          "name": "stripe",
          "config": {
            "id": "stripe",
            "endpoints": {},
            "schema": {
              "subscription": {
                "fields": {
                  "plan": {
                    "type": "string",
                    "required": true
                  },
                  "referenceId": {
                    "type": "string",
                    "required": true
                  },
                  "stripeCustomerId": {
                    "type": "string",
                    "required": false
                  },
                  "stripeSubscriptionId": {
                    "type": "string",
                    "required": false
                  },
                  "status": {
                    "type": "string",
                    "defaultValue": "incomplete"
                  },
                  "periodStart": {
                    "type": "date",
                    "required": false
                  },
                  "periodEnd": {
                    "type": "date",
                    "required": false
                  },
                  "trialStart": {
                    "type": "date",
                    "required": false
                  },
                  "trialEnd": {
                    "type": "date",
                    "required": false
                  },
                  "cancelAtPeriodEnd": {
                    "type": "boolean",
                    "required": false,
                    "defaultValue": false
                  },
                  "seats": {
                    "type": "number",
                    "required": false
                  }
                }
              },
              "user": {
                "fields": {
                  "stripeCustomerId": {
                    "type": "string",
                    "required": false
                  }
                }
              }
            }
          }
        }
      ],
      "emailAndPassword": {
        "enabled": true,
        "requireEmailVerification": true
      },
      "emailVerification": {
        "sendOnSignUp": true,
        "autoSignInAfterVerification": true
      },
      "session": {
        "expiresIn": 604800,
        "updateAge": 86400
      },
      "advanced": {
        "defaultCookieAttributes": {
          "sameSite": "lax",
          "secure": false,
          "httpOnly": true
        }
      },
      "socialProviders": {
        "google": {
          "prompt": "select_account consent",
          "clientId": "[REDACTED]",
          "clientSecret": "[REDACTED]",
          "scope": [
            "openid",
            "email",
            "profile",
            "https://www.googleapis.com/auth/gmail.send"
          ],
          "accessType": "offline"
        }
      },
      "databaseHooks": {
        "account": {
          "create": {}
        }
      },
      "hooks": {}
    }
  }
}

Which area(s) are affected? (Select all that apply)

Types

Auth config (if applicable)

import {
  BETTER_AUTH_SECRET,
  BETTER_AUTH_URL,
  CORS_ORIGIN,
  GOOGLE_CLIENT_ID,
  GOOGLE_CLIENT_SECRET,
  IS_PROD,
  REQUIRE_EMAIL_VERIFICATION,
  STRIPE_SECRET_KEY,
  STRIPE_WEBHOOK_SECRET,
} from "@/config/constants";
import {
  addProviderEmail,
  ProviderId,
} from "@/features/user/services/addProviderEmail.service";
import { MailClient } from "@/lib/mail-client";
import { client } from "@/lib/mongo";
import { stripe } from "@better-auth/stripe";
import { userRoleEnum } from "@packages/shared/schemas/user";
import { logger } from "@packages/shared/utils";
import { betterAuth } from "better-auth";
import { mongodbAdapter } from "better-auth/adapters/mongodb";
import { admin, createAuthMiddleware } from "better-auth/plugins";
import Stripe from "stripe";
import { STRIPE_PLANS } from "./stripe";

// Using MailClient object-based approach
const stripeClient = new Stripe(STRIPE_SECRET_KEY, {
  apiVersion: "2025-09-30.clover", // Latest API version as of Stripe SDK v19
});
export const auth = betterAuth({
  database: mongodbAdapter(client),
  secret: BETTER_AUTH_SECRET,
  baseURL: BETTER_AUTH_URL,
  trustedOrigins: [CORS_ORIGIN],
  errorURL: CORS_ORIGIN,
  user: {
    additionalFields: {
      isOnboardingComplete: {
        type: "boolean",
        defaultValue: false,
        required: false,
      },
      timezone: {
        type: "string",
        defaultValue: "Europe/London",
        required: false,
      },
    },
  },
  account: {
    accountLinking: {
      enabled: true,
      allowDifferentEmails: false,
      updateUserInfoOnLink: true,
    },
  },
  plugins: [
    admin({
      defaultRole: userRoleEnum.USER,
      adminRoles: [userRoleEnum.ADMIN],
    }),
    stripe({
      stripeClient,
      stripeWebhookSecret: STRIPE_WEBHOOK_SECRET,
      createCustomerOnSignUp: true,
      subscription: {
        enabled: true,
        plans: STRIPE_PLANS,
      },
    }),
  ],
  emailAndPassword: {
    enabled: true,
    requireEmailVerification: REQUIRE_EMAIL_VERIFICATION,
    sendResetPassword: async ({ user, url, token }, request) => {
      await MailClient.sendPasswordResetEmail(user.email, user.name, url);
    },
  },
  emailVerification: {
    sendOnSignUp: true,
    autoSignInAfterVerification: true,
    sendVerificationEmail: async ({ user, url, token }, request) => {
      await MailClient.sendVerificationEmail(user.email, user.name, url);
    },
  },
  session: {
    expiresIn: 60 * 60 * 24 * 7, // 7 days
    updateAge: 60 * 60 * 24, // 1 day
  },
  advanced: {
    defaultCookieAttributes: {
      sameSite: "lax",
      secure: IS_PROD,
      httpOnly: true,
    },
  },
  socialProviders: {
    google: {
      prompt: "select_account consent",
      clientId: GOOGLE_CLIENT_ID,
      clientSecret: GOOGLE_CLIENT_SECRET,
      scope: [
        "openid",
        "email",
        "profile",
        "https://www.googleapis.com/auth/gmail.send",
      ],
      accessType: "offline", // Required to get refresh tokens
    },
    // microsoft: {
    //   clientId: MICROSOFT_CLIENT_ID,
    //   clientSecret: MICROSOFT_CLIENT_SECRET,
    //   tenantId: "common",
    //   prompt: "select_account",
    // },
  },
  databaseHooks: {
    account: {
      create: {
        after: async (account) => {
          // skip if providerId is credentials
          if (account.providerId === "credentials") {
            return;
          }

          // Use service to add provider email
          await addProviderEmail(
            account.id,
            account.providerId as ProviderId,
            account.accessToken || undefined
          );
        },
      },
    },
  },
  hooks: {
    before: createAuthMiddleware(async (ctx) => {
      if (ctx.path === "/error") {
        const { error } = ctx.query as { error?: string };
        logger.error(new Error("Auth error"), "AUTH");

        let redirectUrl = `${CORS_ORIGIN}/?error=${encodeURIComponent(
          "Authentication Error"
        )}&error_description=${encodeURIComponent("Failed to authenticate")}`;

        if (error === "banned") {
          redirectUrl = `${CORS_ORIGIN}/?error=${encodeURIComponent(
            "You have been banned"
          )}&error_description=${encodeURIComponent("Contact support team")}`;
        }

        throw ctx.redirect(redirectUrl);
      }
    }),
  },
});

// Use the shared types for consistency
export type Session = typeof auth.$Infer.Session.session;
export type User = typeof auth.$Infer.Session.user;

Additional context

The inferred type of 'auth' cannot be named without a reference to '.pnpm/@better-auth+core@1.3.33_@better-auth+utils@0.3.0_@better-fetch+fetch@1.1.18_better-cal_7d993e08fee368dcdde874190a187847/node_modules/@better-auth/core/db/adapter'. This is likely not portable. A type annotation is necessary.ts(2742)

now:
type User = {
id: string;
createdAt: Date;
updatedAt: Date;
email: string;
emailVerified: boolean;
name: string;
image?: string | null | undefined;
isOnboardingComplete: boolean | null | undefined;
timezone: string | null | undefined;
banned: boolean | null | undefined;
role?: string | null | undefined;
banReason?: string | null | undefined;
banExpires?: Date | null | undefined;
}

when used:
export const auth :Auth = ...
type User = {
id: string;
createdAt: Date;
updatedAt: Date;
email: string;
emailVerified: boolean;
name: string;
image?: string | null | undefined;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    lockedLocked conversations after being closed for 7 days

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions