[GH-ISSUE #4762] Password hash error after supabase migration #10053

Closed
opened 2026-04-13 05:57:28 -05:00 by GiteaMirror · 4 comments
Owner

Originally created by @Stealthwriter on GitHub (Sep 19, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/4762

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

I get this error after supabase migration:

SERVER_ERROR: [Error [BetterAuthError]: Invalid password hash] { cause: undefined }
POST /api/auth/sign-in/email 500 in 1563ms
POST /auth/login 200 in 1722ms

what could be the issue?

I'm using nextjs and I followed the migration guide from supabase to better auth, the tables were created and the users and accounts were migrated but when I sign in with a user a get this error

Current vs. Expected behavior

User should sign in

What version of Better Auth are you using?

1.3.12

System info

{
  "system": {
    "platform": "win32",
    "arch": "x64",
    "version": "Windows 11 Home",
    "release": "10.0.26100",
    "cpuCount": 24,
    "cpuModel": "Intel(R) Core(TM) Ultra 9 275HX",
    "totalMemory": "31.43 GB",
    "freeMemory": "14.47 GB"
  },
  "node": {
    "version": "v22.19.0",
    "env": "development"
  },
  "packageManager": {
    "name": "npm",
    "version": "10.9.3"
  },
  "frameworks": [
    {
      "name": "next",
      "version": "15.5.2"
    },
    {
      "name": "react",
      "version": "19.1.1"
    }
  ],
  "databases": [
    {
      "name": "pg",
      "version": "^8.16.3"
    }
  ],
  "betterAuth": {
    "version": "^1.3.12",
    "config": {
      "emailAndPassword": {
        "enabled": true
      },
      "database": {
        "_events": {},
        "_eventsCount": 0,
        "options": {
          "connectionString": "[REDACTED]",
          "max": 10,
          "min": 0,
          "maxUses": null,
          "allowExitOnIdle": false,
          "maxLifetimeSeconds": 0,
          "idleTimeoutMillis": 10000
        },
        "_clients": [],
        "_idle": [],
        "_expired": {},
        "_pendingQueue": [],
        "ending": false,
        "ended": false
      },
      "socialProviders": {
        "google": {
          "clientId": "[REDACTED]",
          "clientSecret": "[REDACTED]"
        }
      },
      "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. 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"
            },
            "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
                  }
                }
              }
            }
          }
        },
        {
          "name": "anonymous",
          "config": {
            "id": "anonymous",
            "endpoints": {},
            "hooks": {
              "after": [
                {}
              ]
            },
            "schema": {
              "user": {
                "fields": {
                  "isAnonymous": {
                    "type": "boolean",
                    "required": false
                  }
                }
              }
            },
            "$ERROR_CODES": {
              "FAILED_TO_CREATE_USER": "Failed to create user",
              "COULD_NOT_CREATE_SESSION": "Could not create session",
              "ANONYMOUS_USERS_CANNOT_SIGN_IN_AGAIN_ANONYMOUSLY": "Anonymous users cannot sign in again anonymously"
            }
          }
        }
      ]
    }
  }
}

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

Backend

Auth config (if applicable)

import { betterAuth } from "better-auth"
export const auth = betterAuth({
  emailAndPassword: {  
    enabled: true
  },
});

Additional context

No response

Originally created by @Stealthwriter on GitHub (Sep 19, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/4762 ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce I get this error after supabase migration: SERVER_ERROR: [Error [BetterAuthError]: Invalid password hash] { cause: undefined } POST /api/auth/sign-in/email 500 in 1563ms POST /auth/login 200 in 1722ms what could be the issue? I'm using nextjs and I followed the migration guide from supabase to better auth, the tables were created and the users and accounts were migrated but when I sign in with a user a get this error ### Current vs. Expected behavior User should sign in ### What version of Better Auth are you using? 1.3.12 ### System info ```bash { "system": { "platform": "win32", "arch": "x64", "version": "Windows 11 Home", "release": "10.0.26100", "cpuCount": 24, "cpuModel": "Intel(R) Core(TM) Ultra 9 275HX", "totalMemory": "31.43 GB", "freeMemory": "14.47 GB" }, "node": { "version": "v22.19.0", "env": "development" }, "packageManager": { "name": "npm", "version": "10.9.3" }, "frameworks": [ { "name": "next", "version": "15.5.2" }, { "name": "react", "version": "19.1.1" } ], "databases": [ { "name": "pg", "version": "^8.16.3" } ], "betterAuth": { "version": "^1.3.12", "config": { "emailAndPassword": { "enabled": true }, "database": { "_events": {}, "_eventsCount": 0, "options": { "connectionString": "[REDACTED]", "max": 10, "min": 0, "maxUses": null, "allowExitOnIdle": false, "maxLifetimeSeconds": 0, "idleTimeoutMillis": 10000 }, "_clients": [], "_idle": [], "_expired": {}, "_pendingQueue": [], "ending": false, "ended": false }, "socialProviders": { "google": { "clientId": "[REDACTED]", "clientSecret": "[REDACTED]" } }, "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. 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" }, "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 } } } } } }, { "name": "anonymous", "config": { "id": "anonymous", "endpoints": {}, "hooks": { "after": [ {} ] }, "schema": { "user": { "fields": { "isAnonymous": { "type": "boolean", "required": false } } } }, "$ERROR_CODES": { "FAILED_TO_CREATE_USER": "Failed to create user", "COULD_NOT_CREATE_SESSION": "Could not create session", "ANONYMOUS_USERS_CANNOT_SIGN_IN_AGAIN_ANONYMOUSLY": "Anonymous users cannot sign in again anonymously" } } } ] } } } ``` ### Which area(s) are affected? (Select all that apply) Backend ### Auth config (if applicable) ```typescript import { betterAuth } from "better-auth" export const auth = betterAuth({ emailAndPassword: { enabled: true }, }); ``` ### Additional context _No response_
GiteaMirror added the lockedbug labels 2026-04-13 05:57:28 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Sep 19, 2025):

Hi @Stealthwriter! I'm Dosu and I’m helping the better-auth team.

The error happens because Better Auth expects password hashes in its own scrypt-based format: a hex-encoded salt and key separated by a colon (like salt:key). Supabase, by default, uses bcrypt for password hashing, which is a completely different format. When you migrate users from Supabase, their bcrypt hashes are not compatible with Better Auth's verification logic, so sign-in fails with an "Invalid password hash" error see code.

To fix this, you need to re-hash all migrated users' passwords using Better Auth's hashing function. The standard approach is to require users to reset their passwords after migration. Once they set a new password, it will be stored in the correct format and sign-in will work see docs.

There is currently no built-in migration tool to convert bcrypt hashes to the scrypt format Better Auth expects. If you want a seamless experience, you could implement a password reset flow for all migrated users.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X

<!-- gh-comment-id:3310918285 --> @dosubot[bot] commented on GitHub (Sep 19, 2025): <!-- Greeting --> Hi @Stealthwriter! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the better-auth team. <!-- Answer --> The error happens because Better Auth expects password hashes in its own scrypt-based format: a hex-encoded salt and key separated by a colon (like `salt:key`). Supabase, by default, uses bcrypt for password hashing, which is a completely different format. When you migrate users from Supabase, their bcrypt hashes are not compatible with Better Auth's verification logic, so sign-in fails with an "Invalid password hash" error [see code](https://github.com/better-auth/better-auth/blob/57510365a393bca2f6a37e50c43571651b121978/packages/better-auth/src/crypto/password.ts). To fix this, you need to re-hash all migrated users' passwords using Better Auth's hashing function. The standard approach is to require users to reset their passwords after migration. Once they set a new password, it will be stored in the correct format and sign-in will work [see docs](https://github.com/better-auth/better-auth/pull/3641). There is currently no built-in migration tool to convert bcrypt hashes to the scrypt format Better Auth expects. If you want a seamless experience, you could implement a password reset flow for all migrated users. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/c0d6ed5c-7e11-4edf-a322-621161f87abc?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/c0d6ed5c-7e11-4edf-a322-621161f87abc?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/c0d6ed5c-7e11-4edf-a322-621161f87abc?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/c0d6ed5c-7e11-4edf-a322-621161f87abc?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/c0d6ed5c-7e11-4edf-a322-621161f87abc?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/c0d6ed5c-7e11-4edf-a322-621161f87abc?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/c0d6ed5c-7e11-4edf-a322-621161f87abc?feedback_type=other)</sup>&nbsp;&nbsp;[![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/4762)
Author
Owner

@Kinfe123 commented on GitHub (Sep 19, 2025):

can you please inspect what is stored on supabase ?

<!-- gh-comment-id:3311500216 --> @Kinfe123 commented on GitHub (Sep 19, 2025): can you please inspect what is stored on supabase ?
Author
Owner

@Lantianyou commented on GitHub (Sep 21, 2025):

For example, $2a$10$B2RhqyPFNX2JYDexzuotjuU7pOGQXmB4sR0ydLUFFup6ko6.tgRy6

<!-- gh-comment-id:3316200595 --> @Lantianyou commented on GitHub (Sep 21, 2025): For example, $2a$10$B2RhqyPFNX2JYDexzuotjuU7pOGQXmB4sR0ydLUFFup6ko6.tgRy6
Author
Owner

@Lantianyou commented on GitHub (Sep 21, 2025):

Supbase use bcrypt, differnt from better auth default, need additional setup guide here in doc https://www.better-auth.com/docs/guides/supabase-migration-guide

<!-- gh-comment-id:3316201492 --> @Lantianyou commented on GitHub (Sep 21, 2025): Supbase use bcrypt, differnt from better auth default, need additional setup guide here in doc https://www.better-auth.com/docs/guides/supabase-migration-guide
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#10053