get-convex / convex-auth

Library for built-in auth
https://labs.convex.dev/auth
51 stars 15 forks source link

Exceptions thrown in ConvexCredentials.authorize() are unhandled #65

Open doublemarked opened 1 month ago

doublemarked commented 1 month ago

Overview

Exceptions (including ConvexError) are unhandled when thrown from a ConvexCredentials.authorize() method.

Setup

export const { auth, signIn, signOut, store } = convexAuth({
    providers: [
        ConvexCredentials({
            id: 'simple-auth',
            authorize: async () => {
                throw new ConvexError('Testing for @sshader')
            },
        }),
    ],
})

Outcome

Screenshot 2024-09-03 at 9 51 44 PM

Expected outcome

At minimum, the exception should be caught by Convex. But ideally, throwing an exception from authorize() should bubble up to the client side so that the client can handle the error. We should be able to use exceptions or some other mechanism to communicate failure conditions to the client during authorize() in order to better control the authorization process.

sshader commented 1 month ago

I believe this is just the logging that's confusing -- it's logging that the server function threw an error, but the error is still catchable on the client (so it's an uncaught error from the perspective of the server, but not necessarily from the perspective of the client, even though this message will appear in client logs).

The ConvexError is catchable on the client (here's the sample code I was testing with)

        onClick={() =>
          void signIn("simple-auth").catch((e) => {
            if (e instanceof ConvexError) {
              window.alert(`Convex Error!\nData: ${JSON.stringify(e.data)}`);
            } else {
              console.error("#### caught unknown error", e);
              throw e;
            }
          })
        }

The Convex Auth library could be wrapping all non-ConvexErrors thrown during authorize in an error with a prettier message (like "Authorization failed" as opposed to just "Server Error"), but throwing custom errors from authorize that the client can handle should be working as intended.

doublemarked commented 1 month ago

@sshader I really appreciate how responsive you are! I also thought this at first, but I get weird unhandled errors on the client side too. If it's working for you it may be somehow environment-specific, I'm not sure. Here's the sample code I just tried and the error that happened:

    function dotest() {
        signIn('simple-auth').catch((e) => {
            if (e instanceof ConvexError) {
                window.alert('Convex Error!')
                window.alert(`Convex Error!\nData: ${JSON.stringify(e.data)}`)
            } else {
                console.error('#### caught unknown error', e)
                throw e
            }
        })
    }

There is no alert fired. I do get this on the browser dev console:

#### caught unknown error SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data [app-index.tsx:25:19](http://localhost:3000/turbopack/[project]/node_modules/.pnpm/next@14.2.7_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/src/client/app-index.tsx)
Uncaught (in promise) SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data

So you see - it's not getting a ConvexError, it's getting some secondary exception that has been fired due to JSON.parse throwing.

pdesign commented 1 month ago

this is so frustrating... its giving uncought error on the client side... and even though you catch it... it logs to the console... and also gives a file not found error by looking for node_modules folder up two folder level....

[CONVEX A(auth:signIn)] [Request ID: a63d2a4d77b8e854] Server Error Uncaught Error: InvalidAccountId at retrieveAccount (../../node_modules/@convex-dev/auth/dist/server/implementation/index.js:343:4) at async authorize [as authorize] (../../node_modules/@convex-dev/auth/dist/providers/Password.js:65:20) at async handleCredentials (../../node_modules/@convex-dev/auth/dist/server/implementation/signIn.js:102:19) at async handler (../../node_modules/@convex-dev/auth/dist/server/implementation/index.js:245:20) Error: ENOENT: no such file or directory, open '/Users/macosuser/www/projects/eKeepConvex/node_modules/@convex-dev/auth/dist/server/implementation/index.js' at Object.readFileSync (node:fs:448:20) at getCodeFrame (/Users/macosuser/www/projects/eKeepConvex/mobile/ekeep/node_modules/metro/src/Server.js:949:18) at Server._symbolicate (/Users/macosuser/www/projects/eKeepConvex/mobile/ekeep/node_modules/metro/src/Server.js:1026:22) at processTicksAndRejections (node:internal/process/task_queues:95:5) at Server._processRequest (/Users/macosuser/www/projects/eKeepConvex/mobile/ekeep/node_modules/metro/src/Server.js:419:7) { errno: -2, code: 'ENOENT', syscall: 'open', path: '/Users/macosuser/www/projects/eKeepConvex/node_modules/@convex-dev/auth/dist/server/implementation/index.js' } Error: ENOENT: no such file or directory, open '/Users/macosuser/www/projects/eKeepConvex/node_modules/@convex-dev/auth/dist/providers/Password.js' at Object.readFileSync (node:fs:448:20) at getCodeFrame (/Users/macosuser/www/projects/eKeepConvex/mobile/ekeep/node_modules/metro/src/Server.js:949:18) at Server._symbolicate (/Users/macosuser/www/projects/eKeepConvex/mobile/ekeep/node_modules/metro/src/Server.js:1026:22) at processTicksAndRejections (node:internal/process/task_queues:95:5) at Server._processRequest (/Users/macosuser/www/projects/eKeepConvex/mobile/ekeep/node_modules/metro/src/Server.js:419:7) { errno: -2, code: 'ENOENT', syscall: 'open', path: '/Users/macosuser/www/projects/eKeepConvex/node_modules/@convex-dev/auth/dist/providers/Password.js' } Error: ENOENT: no such file or directory, open '/Users/macosuser/www/projects/eKeepConvex/node_modules/@convex-dev/auth/dist/server/implementation/signIn.js' at Object.readFileSync (node:fs:448:20) at getCodeFrame (/Users/macosuser/www/projects/eKeepConvex/mobile/ekeep/node_modules/metro/src/Server.js:949:18) at Server._symbolicate (/Users/macosuser/www/projects/eKeepConvex/mobile/ekeep/node_modules/metro/src/Server.js:1026:22) at processTicksAndRejections (node:internal/process/task_queues:95:5) at Server._processRequest (/Users/macosuser/www/projects/eKeepConvex/mobile/ekeep/node_modules/metro/src/Server.js:419:7) { errno: -2, code: 'ENOENT', syscall: 'open', path: '/Users/macosuser/www/projects/eKeepConvex/node_modules/@convex-dev/auth/dist/server/implementation/signIn.js' } Error: ENOENT: no such file or directory, open '/Users/macosuser/www/projects/eKeepConvex/node_modules/@convex-dev/auth/dist/server/implementation/index.js' at Object.readFileSync (node:fs:448:20) at getCodeFrame (/Users/macosuser/www/projects/eKeepConvex/mobile/ekeep/node_modules/metro/src/Server.js:949:18) at Server._symbolicate (/Users/macosuser/www/projects/eKeepConvex/mobile/ekeep/node_modules/metro/src/Server.js:1026:22) at processTicksAndRejections (node:internal/process/task_queues:95:5) at Server._processRequest (/Users/macosuser/www/projects/eKeepConvex/mobile/ekeep/node_modules/metro/src/Server.js:419:7) { errno: -2, code: 'ENOENT', syscall: 'open', path: '/Users/macosuser/www/projects/eKeepConvex/node_modules/@convex-dev/auth/dist/server/implementation/index.js' }

sshader commented 1 month ago

@doublemarked -- could you share more about what browser you're using + what version of Convex + Convex Auth, because I can't reproduce this (in case it is environment specific). I'm also curious what the dashboard logs say (i.e. do they show your ConvexError, or something else) to rule out the possibility that you're hitting some other error before we even hit the ConvexError.

Also noted that the logging the error is frustrating -- will file that internally as an area of improvement for Convex since it's pretty separate from Convex Auth.

doublemarked commented 1 month ago

Hey @sshader! 👋

I've created for you an extremely distilled sample project that reproduces this: https://github.com/doublemarked/convex-auth-error

Let me know if you're able to reproduce using that project. I am testing with Node v20.

pdesign commented 1 month ago

I have been using Convex Auth with React Native as i got those error logs...

labigalini commented 1 month ago

Hey just wanted to share that trying to throw an error on createOrUpdateUser:

export const { auth, signIn, signOut, store } = convexAuth({
  providers: [ResendOTP],
  callbacks: {
    createOrUpdateUser(_ctx, args) {
      if (args.existingUserId) {
        return Promise.resolve(args.existingUserId);
      }

      // Do not allow new users to sign up
      throw new ConvexError("New users not allowed");
    },
  },
});

Also ends up with the same error mentioned by @doublemarked caught on the client side:

SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data
pdesign commented 1 month ago

@labigalini why in earth a thumb down??

pdesign commented 21 hours ago

still not solved