lucia icon indicating copy to clipboard operation
lucia copied to clipboard

[Bug]: switch to hash @node-rs/argon2 breaks sveltekit production builds

Open vhochstein opened this issue 1 year ago • 23 comments

Package

lucia

Describe the bug

Latest versions of Lucia are relying upon: import { hash } from "@node-rs/argon2"; That one is breaking npm run build for sveltekit projects. Please see error below. node: v20.11.1

/Users/volkerhochstein/projects/node/magic-pull/node_modules/@node-rs/argon2-android-arm-eabi/argon2.android-arm-eabi.node error during build: RollupError: Unexpected character '\u{7f}' at getRollupError (file:///Users/volkerhochstein/projects/node/magic-pull/node_modules/rollup/dist/es/shared/parseAst.js:380:41) at ParseError.initialise (file:///Users/volkerhochstein/projects/node/magic-pull/node_modules/rollup/dist/es/shared/node-entry.js:11172:28) at convertNode (file:///Users/volkerhochstein/projects/node/magic-pull/node_modules/rollup/dist/es/shared/node-entry.js:12914:1

Looks like there is already a corresponding ticket open in node-rs/argon2, https://github.com/napi-rs/node-rs/issues/816

If I use "old style" to create hash and verification eg: return await new Argon2id().hash(password); and remove import for node-rs/argon2 prod build npm task is working

building in dev mode is working without any issue for both hashing solutions

What do you suggest to do, currently I do not know how to work around this ?

Thanks a lot for your support

vhochstein avatar May 12 '24 13:05 vhochstein

Tried now other node versions eg. node 18 and tried other machines to build. But always the same issue.

Any help would be greatly appreciated.

vhochstein avatar May 14 '24 06:05 vhochstein

Is it an issue with Lucia or Oslo?

pilcrowonpaper avatar May 14 '24 08:05 pilcrowonpaper

Not sure.. I ve just tried it with your example project: https://github.com/lucia-auth/examples/tree/main/sveltekit/username-and-password

if you install: npm i -D @sveltejs/adapter-node adjust svelteConfig to adapter-node (just changing import)

switch hash algorithm to: await hash(password, { // recommended minimum parameters memoryCost: 19456, timeCost: 2, outputLen: 32, parallelism: 1 });

npm run build

I am getting same error

vhochstein avatar May 14 '24 14:05 vhochstein

Also running into this issue for what it's worth, but even running locally doesn't work on my end. Currently looking into a work around

chaseweaver avatar May 14 '24 14:05 chaseweaver

I ve made a mistake in my own project..., let me correct my comment: If I switch to oslo Argon hash, I can build for production, so same result as for example project.

so at least I have a workaround for the moment.

vhochstein avatar May 14 '24 15:05 vhochstein

Ah so you're using the adapter-node. Is Oslo/Argon installed as a dev dependency?

pilcrowonpaper avatar May 14 '24 23:05 pilcrowonpaper

Argon is neither listed as dev nor "standard" dependency. oslo is listed as "standard" dependency. Simlar to: https://github.com/lucia-auth/examples/tree/main/sveltekit/username-and-password

vhochstein avatar May 16 '24 08:05 vhochstein

I'm not really following here. Is it an issue with Oslo or napi-rs? Lucia doesn't have a dependency on the latter

pilcrowonpaper avatar May 16 '24 08:05 pilcrowonpaper

Its about these imports given in code example on the following page: https://lucia-auth.com/tutorials/username-and-password/sveltekit import { hash } from "@node-rs/argon2"; import { verify } from "@node-rs/argon2";

vhochstein avatar May 16 '24 08:05 vhochstein

[sveltekit]

having same issue here is the errors that i'm receiving :

the first : @node-rs/argon2-darwin-x64

✘ [ERROR] No loader is configured for ".node" files: node_modules/.pnpm/@[email protected]/node_modules/@node-rs/argon2-darwin-x64/argon2.darwin-x64.node

    node_modules/.pnpm/@[email protected]/node_modules/@node-rs/argon2/index.js:159:36:
      159 │             nativeBinding = require('@node-rs/argon2-darwin-x64')

the second : @node-rs/bcrypt-darwin-x64

✘ [ERROR] No loader is configured for ".node" files: node_modules/.pnpm/@[email protected]/node_modules/@node-rs/bcrypt-darwin-x64/bcrypt.darwin-x64.node

    node_modules/.pnpm/@[email protected]/node_modules/@node-rs/bcrypt/binding.js:153:36:
      153 │             nativeBinding = require('@node-rs/bcrypt-darwin-x64')
          ╵      

LargatSeif avatar May 25 '24 11:05 LargatSeif

[sveltekit]

having same issue here is the errors that i'm receiving :

the first : @node-rs/argon2-darwin-x64

✘ [ERROR] No loader is configured for ".node" files: node_modules/.pnpm/@[email protected]/node_modules/@node-rs/argon2-darwin-x64/argon2.darwin-x64.node

    node_modules/.pnpm/@[email protected]/node_modules/@node-rs/argon2/index.js:159:36:
      159 │             nativeBinding = require('@node-rs/argon2-darwin-x64')

the second : @node-rs/bcrypt-darwin-x64

✘ [ERROR] No loader is configured for ".node" files: node_modules/.pnpm/@[email protected]/node_modules/@node-rs/bcrypt-darwin-x64/bcrypt.darwin-x64.node

    node_modules/.pnpm/@[email protected]/node_modules/@node-rs/bcrypt/binding.js:153:36:
      153 │             nativeBinding = require('@node-rs/bcrypt-darwin-x64')
          ╵      

@LargatSeif Try adding this to your optimizeDeps.exclude in your vite.config.ts and see if that fixes it

optimizeDeps: {
    exclude: ['@node-rs/argon2', '@node-rs/bcrypt']
},

chaseweaver avatar May 25 '24 14:05 chaseweaver

[sveltekit]

having same issue here is the errors that i'm receiving :

the first : @node-rs/argon2-darwin-x64

✘ [ERROR] No loader is configured for ".node" files: node_modules/.pnpm/@[email protected]/node_modules/@node-rs/argon2-darwin-x64/argon2.darwin-x64.node

    node_modules/.pnpm/@[email protected]/node_modules/@node-rs/argon2/index.js:159:36:
      159 │             nativeBinding = require('@node-rs/argon2-darwin-x64')

the second : @node-rs/bcrypt-darwin-x64

✘ [ERROR] No loader is configured for ".node" files: node_modules/.pnpm/@[email protected]/node_modules/@node-rs/bcrypt-darwin-x64/bcrypt.darwin-x64.node

    node_modules/.pnpm/@[email protected]/node_modules/@node-rs/bcrypt/binding.js:153:36:
      153 │             nativeBinding = require('@node-rs/bcrypt-darwin-x64')
          ╵      

@LargatSeif Try adding this to your optimizeDeps.exclude in your vite.config.ts and see if that fixes it

optimizeDeps: {
    exclude: ['@node-rs/argon2', '@node-rs/bcrypt']
},

this worked thanks 🙏

LargatSeif avatar May 25 '24 22:05 LargatSeif

Is this a bug or just something we need to add to the docs?

pilcrowonpaper avatar Jun 08 '24 02:06 pilcrowonpaper

Something funky must have happened with one of the @node-rs packages at some point but is fixed now. It appears as though those packages are no longer required to be in optimizeDeps (at least the few projects I work on no longer seem to need it). I cannot replicate the original issue any longer either.

Probably safe to call it "not a bug" unless @vhochstein is still having issues.

chaseweaver avatar Jun 09 '24 02:06 chaseweaver

I get a similar error when using it in Next.js. I'm sure this is related to node-rs/argon2 as I got a similar error when using the below code:

import { hash } from "@node-rs/argon2";
...
const passwordHash = await hash(password, {
    // recommended minimum parameters
    memoryCost: 19456,
    timeCost: 2,
    outputLen: 32,
    parallelism: 1
});

When I following the Next.js example with oslo/password:

import { Argon2id } from "oslo/password";
...
// hasing pw
const hashedPassword = await new Argon2id().hash(password);

// verifying pw
const validPassword = await new Argon2id().verify(existingUser.password, password);

I get this error image

btw, huge fan of your library!

holahoon avatar Jun 10 '24 19:06 holahoon

The "Unexpected character" issue seems to be an issue with bundlers not handling .node files, see https://github.com/vitejs/vite/issues/14289. Some users in that thread have found workarounds

EDIT: I fixed it in SvelteKit by explicitly adding @node-rs/argon2 to "dependencies" of my SvelteKit app (even though it's the dependancy of a library package in my monorepo) and adding @node-rs/argon2 to rollupOptions.external in my Vite config. I can now use @node-rs/argon2 (or oslo/password) server-side in my app.

njanke96 avatar Jun 14 '24 23:06 njanke96

Hi, I am getting this error, but for Next.JS:

│   ▲ Next.js 14.2.4
│ 
│    Creating an optimized production build ...
│ Failed to compile.
│ 
│ ../../packages/api/node_modules/@node-rs/argon2-linux-x64-gnu/argon2.linux-x64-gnu.node
│ Module parse failed: Unexpected character '' (1:0)
│ You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
│ (Source code omitted for this binary file)

NOTE: as per the documentation on lucia, I have already added

experimental: {
    serverComponentsExternalPackages: ["@node-rs/argon2"],
  },

to my next.config.js file, but no luck

dBianchii avatar Jul 03 '24 15:07 dBianchii

OOOKK, Sooo...

I discovered that the problem was that I was using @node-rs/argon2 in a separate package from my monorepo, that was being used by my Next.JS app. (@acme/api package from this monorepo starter: https://github.com/noxify/t3-turbo-lucia)

So, since @node-rs/argon2 wasn't a direct dependency, I guess that serverComponentsExternalPackages: ["@node-rs/argon2"], config for nextjs was being pretty much ignored.

Solution: I installed @node-rs/argon2 directly on my next.js app, so it appears on its package.json. Then, the serverComponentsExternalPackages works correctly. If you are on a monorepo, make sure this package is installed directly, even if it is only being undirectly being used by next.js

dBianchii avatar Jul 03 '24 16:07 dBianchii

Something funky must have happened with one of the @node-rs packages at some point but is fixed now. It appears as though those packages are no longer required to be in optimizeDeps (at least the few projects I work on no longer seem to need it). I cannot replicate the original issue any longer either.

Probably safe to call it "not a bug" unless @vhochstein is still having issues.

I still get this problem when using adapter-cloudflare. Adding the packages to the exclude list in optimizeDeps does not solve it. I attached my package.json and here's the relevant output:

> Using @sveltejs/adapter-cloudflare
✘ [ERROR] No loader is configured for ".node" files: node_modules/@node-rs/argon2-linux-x64-musl/argon2.linux-x64-musl.node

    node_modules/@node-rs/argon2/index.js:209:38:
      209 │ ...        nativeBinding = require('@node-rs/argon2-linux-x64-musl')
          ╵                                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


✘ [ERROR] No loader is configured for ".node" files: node_modules/@node-rs/argon2-linux-x64-gnu/argon2.linux-x64-gnu.node

    node_modules/@node-rs/argon2/index.js:222:38:
      222 │ ...         nativeBinding = require('@node-rs/argon2-linux-x64-gnu')
          ╵                                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


✘ [ERROR] No loader is configured for ".node" files: node_modules/@node-rs/bcrypt-linux-x64-musl/bcrypt.linux-x64-musl.node

    node_modules/@node-rs/bcrypt/binding.js:199:38:
      199 │ ...        nativeBinding = require('@node-rs/bcrypt-linux-x64-musl')
          ╵                                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


✘ [ERROR] No loader is configured for ".node" files: node_modules/@node-rs/bcrypt-linux-x64-gnu/bcrypt.linux-x64-gnu.node

    node_modules/@node-rs/bcrypt/binding.js:210:38:
      210 │ ...         nativeBinding = require('@node-rs/bcrypt-linux-x64-gnu')
          ╵                                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


error during build:
Error: Bundling with esbuild failed with 4 errors
    at adapt (file:///$PATH/concertdb/node_modules/@sveltejs/adapter-cloudflare/index.js:140:11)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async adapt (file:///$PATH/concertdb/node_modules/@sveltejs/kit/src/core/adapt/index.js:38:2)
    at async finalise (file:///$PATH/concertdb/node_modules/@sveltejs/kit/src/exports/vite/index.js:890:7)
    at async Object.handler (file:///$PATH/concertdb/node_modules/@sveltejs/kit/src/exports/vite/index.js:920:5)
    at async PluginDriver.hookParallel (file:///$PATH/concertdb/node_modules/rollup/dist/es/shared/node-entry.js:19794:17)
    at async Object.close (file:///$PATH/concertdb/node_modules/rollup/dist/es/shared/node-entry.js:20729:13)
    at async build (file:///$PATH/concertdb/node_modules/vite/dist/node/chunks/dep-mCdpKltl.js:65142:17)
    at async CAC.<anonymous> (file:///$PATH/concertdb/node_modules/vite/dist/node/cli.js:828:5)
)

package.json

SolidTux avatar Aug 02 '24 12:08 SolidTux

@SolidTux @node-rs/argon2 (and a lot hashing libs) doesn't work in CF

pilcrowonpaper avatar Aug 03 '24 00:08 pilcrowonpaper

serverComponentsExternalPackages: ["@node-rs/argon2"],

thanks @dBianchii it worked for me!

raunak-mishraa avatar Sep 16 '24 17:09 raunak-mishraa

Is there any better solution? I keep bouncing between my app building and not building even though I have all these dependencies in regular dependencies.

"@internationalized/date": "^3.5.5",
"@lucia-auth/adapter-drizzle": "^1.1.0",
		"@neondatabase/serverless": "^0.9.5",
		"@node-rs/argon2": "^1.8.3",
		"@oslojs/crypto": "^1.0.1",
		"@oslojs/encoding": "^1.0.0",
		"@oslojs/jwt": "^0.2.0",
		"@oslojs/oauth2": "^0.5.0",
		"@oslojs/otp": "^1.0.0",
		"@oslojs/webauthn": "^1.0.0",
		"@paralleldrive/cuid2": "^2.2.2",
		"@sveltejs/adapter-node": "^5.2.3",
		"@sveltejs/adapter-vercel": "^5.4.4",
		"oslo": "^1.2.1",
		"pg": "^8.13.0",
		"postgres": "^3.4.4",

BradNut avatar Sep 23 '24 17:09 BradNut

@SolidTux @node-rs/argon2 (and a lot hashing libs) doesn't work in CF

what pure js library would you recommend to replace it?

currently I'm using something like this (just copied it from SO)

import { randomBytes, scryptSync } from 'crypto';

// Pass the password string and get hashed password back
// ( and store only the hashed string in your database)
function encryptPassword(password: string, salt: string) {
	return scryptSync(password, salt, 32).toString('hex');
}

/**
 * Hash password with random salt
 * @return {string} password hash followed by salt
 *  XXXX till 64 XXXX till 32
 *
 */
export function hash(password: string) {
	// Any random string here (ideally should be at least 16 bytes)
	const salt = randomBytes(16).toString('hex');
	return encryptPassword(password, salt) + salt;
}

// fetch the user from your db and then use this function

/**
 * Match password against the stored hash
 */
export function verify(hash: string, password: string) {
	// extract salt from the hashed string
	// our hex password length is 32*2 = 64
	const salt = hash.slice(64);
	const originalPassHash = hash.slice(0, 64);
	const currentPassHash = encryptPassword(password, salt);
	return originalPassHash === currentPassHash;
}

export function simpleHash(password: string) {
	let hash = 0;
	let char = 0;

	if (password.length === 0) return hash.toString();
	for (let index = 0; index < password.length; index++) {
		char = password.charCodeAt(index);
		hash = (hash << 5) - hash + char;
		hash |= 0; // Convert to 32bit integer
	}
	return hash.toString();
}
export function simpleVerify(hash: string, password: string) {
	return hash === simpleHash(password);
}

opensas avatar Oct 23 '24 22:10 opensas

I made a WebAssembly version of @node-rs/argon2 for Cloudflare Workers, though for some reason I am unable to get it to work with Cloudflare Pages.

tropicbliss avatar Mar 14 '25 04:03 tropicbliss

Lucia v3 has been deprecated

pilcrowonpaper avatar Jun 06 '25 17:06 pilcrowonpaper