0

In a react app I need to access MySQL servers, for which I need the user's credentials. In order to avoid having the user enter them every time a connection is opened I'd like to store the password in the browser's password store/manager.

According to MDN all major browsers should support the Credentials Management API. So I tried it like this:

    private requestPassword = (commandId: string, args?: any[]): void => {
        if (args && args.length > 0) {
            // First check if we already have a password and don't ask for it, if so.
            const request: IServicePasswordRequest = args[0];

            navigator.credentials.get({
                password: true,
                mediation: "silent",
            } as any).then((credential) => {
                if (credential) {
                    const id = 0;
                } else {
                    // Opens the password dialog.
                    this.setState({ request }, () => this.dialogRef.current?.open());

                }
            });
        }
    };

    private closePanel = (e: React.SyntheticEvent, props: IButtonProperties): void => {
        // Called when either OK or Cancel was clicked by the user, in the password dialog.
        if (props.id === "ok") {
            const { request } = this.state;
            const options = {
                password: {
                    id: request!.serviceId,
                    name: request!.user,
                    password: "root", // Just for test.
                },
            };

            navigator.credentials.create(options as any).then((credential) => {
                if (credential) {
                    navigator.credentials.store(credential).then((value) => {
                        console.log("Success: " + value);
                    }).catch((e) => {
                        console.log("Error: " + e);
                    });
                }
            });
        }

        this.dialogRef.current?.close();
    };

However there are several problems with that:

  1. The password member (as documented on the CredentialContainer.create() page is unknown to Typescript. I worked around that with an any cast. The returned credential is a PasswordCredential structure, and the content looks fine.
  2. When storing the credentials, the success branch is taken but the promise value is null. Not sure if that's relevant at all.
  3. When I call navigator.credentials.get I never get any credential back. And in fact I'm not surprised. Shouldn't it be necessary to pass in id and user name to find credentials? But the API doesn't allow that.

So, what's the correct approach here?

Mike Lischke
  • 48,925
  • 16
  • 119
  • 181
  • why not use something like _jwt_ if you just prevent reentering passwords? Storing passwords with an experimental tech seems risky. – keremistan May 05 '21 at 08:41
  • Yes, there's a certain risk, but the compatibility table looks very promising. Only old IE is not supported, so I'd say it's pretty safe to start using it. Thanks for suggesting JWT. I never heard of that. I'll read up on it to see if that can provide what I need. Still it would be good to know the right approach for the navigator credentials manager. – Mike Lischke May 05 '21 at 08:48

0 Answers0