davedoesdev / webauthn4js

Web Authentication for Node.js applications

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Looks like the type for WebAuthn4js isnt exported

aircliff01 opened this issue · comments

I am using a typescript project and when i initialize the makeWebAuthn with the config i get the error below:

Return type of public method from exported class has or is using name 'WebAuthn4JS' from external module 
"home/.../node_modules/webauthn4js/index" but cannot be named.ts(4053)

Heres my initialization code:

  async webAuthnInstance(id: string) {
    const lookupRes = // do some lookup of the id

    return makeWebAuthn({
      RPDisplayName: 'displayName',
      RPID: 'something here',
      RPOrigin: 'something here',
      RPIcon: 'something here',
      AuthenticatorSelection: {
        userVerification: 'preferred',
      },
    });
  }

@aircliff thanks for reporting this. I'm not a typescript user normally so that'll be why I missed it. I'll take a look but might not be for a couple of days.

Ok, no worries. I will submit a PR for your review

Ok, no worries. I will submit a PR for your review

I tried opening a PR to export WebAuthn4JS but I got a 403 permission denied:

remote: Permission to davedoesdev/webauthn4js.git denied to Aircliff.
fatal: unable to access 'https://github.com/davedoesdev/webauthn4js.git/': The requested URL returned error: 403

Let me know if you allow contributors or prefer to push it whenever you're ready. I will use the locally linked version in the meantime :)

That is strange - this should be a public repo and I'd appreciate the PR, thanks!
How are you opening the PR? If from the command line does it need a git:// or SSH URL?

@aircliff does v0.0.10 fix it for you?

@aircliff does v0.0.10 fix it for you?

Let me give it a try

hmm so looks like the typing issue is fixed, i'm able to do the import but now i'm getting a different error when trying to create an instance of webauthn, i'm getting this error:

TypeError: webauthn4js_1.default is not a function

Heres my typescript code:

import makeWebAuthn, { WebAuthn4JS } from 'webauthn4js';
//... other imports here ...

async initWebAuthn(clientId: string): Promise<{ webauthn: WebAuthn4JS }> {
    const appData = // lookup the app data using client id

    const webauthn = await makeWebAuthn({          <------ THIS BLOCK IS WHERE ITS FAILING
      RPDisplayName: appData.displayName,
      RPID: appData.id,
      RPOrigin: toLower(appData.origin),
      RPIcon: appData.icon,
      AuthenticatorSelection: {
        userVerification: 'preferred',
      },
      Timeout: DEFAULT_PKEY_CC_TIMEOUT,
    });

    return { webauthn };
  }
  
  async register(clientId: string) {
    const { webauthn, env } = await this.initWebAuthn(clientId); 
    ...
    // create user info and challenge here
    ...
    const { options, sessionData } = await webauthn.beginRegistration(user, cco => {
      cco.excludeCredentials = excludeCreds;
      cco.challenge = challenge;
      return cco;
    });
  }

Any ideas? This is looks like a separate issue though so I think I can close this ticket and open a new separate ticket for this if needed.

This modified version of your code compiles and runs for me:

import makeWebAuthn, { WebAuthn4JS } from 'webauthn4js';

async function initWebAuthn(clientId: string): Promise<{ webauthn: WebAuthn4JS }> {
    const appData = {
        displayName: 'test',
        id: 'test',
        origin: 'http://test:80',
        icon: 'http://test/test.gif'

    }

    const webauthn = await makeWebAuthn({
        RPDisplayName: appData.displayName,
        RPID: appData.id,
        RPOrigin: appData.origin.toLowerCase(),
        RPIcon: appData.icon,
        AuthenticatorSelection: {
            userVerification: 'preferred',
        },
        Timeout: 60000,
    });

    return { webauthn };
}

async function register(clientId: string) {
    const { webauthn } = await initWebAuthn(clientId); 
    const user = {
        id: 'test',
        name: 'test',
        displayName: 'test',
        iconURL: 'http://test/test.gif',
        credentials: []
    };
    const excludeCreds = [];
    const challenge = "";
    // create user info and challenge here
    const { options, sessionData } = await webauthn.beginRegistration(user, cco => {
        cco.excludeCredentials = excludeCreds;
        cco.challenge = challenge;
        return cco;
    });
    return { options, sessionData }
}

console.log(await register('foobar'));

Compile command:

/node_modules/.bin/tsc --module esnext --target es2017 --moduleResolution node test3.ts && mv test3.js test3.mjs

Output:

{
  options: {
    publicKey: {
      challenge: '',
      rp: [Object],
      user: [Object],
      pubKeyCredParams: [Array],
      authenticatorSelection: [Object],
      timeout: 60000
    }
  },
  sessionData: {
    challenge: 'fQKTQYY0VLmD9nD6f1BaAdUnyAi4cd2vUvTMKnFvOgI',
    user_id: 'dGVzdA==',
    userVerification: ''
  }
}

Hi @davedoesdev for some reason in my code using import makeWebAuthn from 'webauthn4js'; didn't work but const makeWebAuthn = require('webauthn4js); worked for me. I think it has something to do with the fact that my tsconfig is using commonjs (Let me know if my assessment is incorrect)

{
  "compilerOptions": {
    "module": "commonjs",
    "declaration": true,
    "removeComments": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "es2017",
    "sourceMap": true,
    "outDir": "./dist",
    "baseUrl": "./",
    "incremental": true,
    "allowSyntheticDefaultImports": false
  },
  "exclude": ["node_modules", "dist"]
}

But I can use the require('webauthn4js) workaround for now, and research a better approach that might work with commonjs at a later time, I will reach out to you and coordinate submitting a PR when I figure out a fix for commonjs modules. Thanks

@aircliff yes that might be related. When I get some time I'll see if I can repro

@aircliff yes that might be related. When I get some time I'll see if I can repro

Sounds good. Thanks

@aircliff I've created this gist: https://gist.github.com/davedoesdev/1aa0b998fd48acfa4897bd67d459d2dc
If you clone it, check over the test.sh script to make sure you're happy with it and then run ./test.sh, does it work for you?

(I've overriden module to esnext - if it compiles ok for you then we can try putting it back to commonjs)

Scratch that - I can repro it now with commonjs module setting.

Might be my fault - definition file is claiming it to be an ES module but it isn't.
Node when importing seems to do the right thing but typescript assumes it has a default property.
I guess I could just add the property but I might google to see if this is a known problem.

@aircliff
I've updated the declaration file according to https://www.typescriptlang.org/docs/handbook/declaration-files/templates/module-d-ts.html

Please try v0.0.12 and add "esModuleInterop": true to your tsconfig

See https://gist.github.com/davedoesdev/1aa0b998fd48acfa4897bd67d459d2dc for a working example.

@aircliff
I've updated the declaration file according to https://www.typescriptlang.org/docs/handbook/declaration-files/templates/module-d-ts.html

Please try v0.0.12 and add "esModuleInterop": true to your tsconfig

See https://gist.github.com/davedoesdev/1aa0b998fd48acfa4897bd67d459d2dc for a working example.

@davedoesdev ok let me give that a shot.

@aircliff
I've updated the declaration file according to https://www.typescriptlang.org/docs/handbook/declaration-files/templates/module-d-ts.html

Please try v0.0.12 and add "esModuleInterop": true to your tsconfig

See https://gist.github.com/davedoesdev/1aa0b998fd48acfa4897bd67d459d2dc for a working example.

Awesome, that solution worked. Thanks very much @davedoesdev. The quick response is very much appreciated. I think we can close this issue now 👍