How to use navigator.credentials to store passwords in a React application?

1.1k Views Asked by At

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?

0

There are 0 best solutions below