javascriptnode.jssecurityexpress

Storing passwords to login to third party APIs


I am writing a trading application using Node & Express for the backend. Each user will have their own login for the application itself, but in order for it to be useful the application also needs to login to the user's brokerage account.

The brokerage account in question has a REST API in which you POST the login and password for that system. That API does not offer SSO or OAuth as an option for authentication. The only means to authenticate is POSTing the uid and password.

So there are two logins involved here: one to my application, and another completely separate login to the brokerage account. Each of those logins uses a different user ID and password.

The problem I'm having is figuring out how to store the password for the brokerage account. I understand that storing a password at all is a bad idea. But if all I store is a salted hash of the brokerage password, I won't be able to reverse that and get the actual password back. Hence, my application won't be able to login to the brokerage account unless the user enters that password again.

(As an aside, there is another program that does this. https://dough.com requires the user to login to dough, and then you also have to login to TD Ameritrade. That logging in twice is what I'm hoping to avoid.)

Is there a reasonable and secure way to store a password for this 3rd party API so that my app can login on the user's behalf without forcing the user to submit the password every time they use my app? I understand there are big security risks here. If the answer is no, then I won't.


Solution

  • Edit & Obligatory - Really the solution is to not do this. While technically possible, it will almost certainly not be implemented correctly & will expose your users' passwords.

    Yes there is, but it's not incredibly easy & implementation is key. The JavaScript OpenPGPJS library is what you want.

    In order for a somewhat secure system, your backend cannot be allowed to decrypt the password. This is where the JS library comes in, which provides PGP crypto via the browser.

    You can base the PGP password off of the user password, or make them provide a new one for decryption. Alternatively, you can generate random keys for the password encryption then create a master key with access to the random ones - encrypting the master with the user input.

    Whichever method you go with you will either need to have them enter the password in order to decrypt the record when needed, or add their password into their local session. The former is secure and the latter has obvious security implications.

    Simple string encrypt using a password as provided by the examples:

    var options, encrypted;
    
    options = {
        data: 'Hello, World!',      // input as String
        passwords: ['secret stuff'] // multiple passwords possible
    };
    
    openpgp.encrypt(options).then(function(ciphertext) {
        encrypted = ciphertext.data; // '-----BEGIN PGP MESSAGE ... END PGP MESSAGE-----'
    });
    

    Decrypt:

    options = {
        message: openpgp.message.readArmored(encrypted), // parse armored message
        password: 'secret stuff'                         // decrypt with password
    };
    
    openpgp.decrypt(options).then(function(plaintext) {
        return plaintext.data; // 'Hello, World!'
    });