authenticationionic3couchdbpouchdb

How to change the http client used by pouchDB?


I am using PouchDB and CouchDB in an ionic application. While I can successfully sync local and remote databases on Chrome and Android, I get unauthorized error on Safari / iOS when I run the sync command. Below is a simplified version of my database service provider.

import PouchDB from 'pouchdb';
import PouchDBAuthentication from 'pouchdb-authentication';

@Injectable()
export class CouchDbServiceProvider {
    private db: any;
    private remote: any;
    constructor() {
      PouchDB.plugin(PouchDBAuthentication);
      this.db = new PouchDB('localdb', {skip_setup: true});
    }
    ...
    login(credentials) {
      let couchDBurl = 'URL of my couchDB database';
      this.remote = new PouchDB(couchDBurl); 
      this.remote.logIn(credentials.username, credentials.password, function (err, response) {
            if (err) { concole.log('login error') }
            else {
                let options = { live: true, retry: true, continuous: true };
                this.db.sync(this.remote, options).on('error', (err_) => { console.log('sync error')});
            }
      })
    }
    ...
}

In the code above, this.remote.logIn(...) is successful but this.db.sync(...) fails. I have checked the requests via the network tab of developer tools and I believe the issue is that the cookie that's retruned in the response header of this.remote.logIn(...) is not used by the subsequent calls (thus the unauthorized error). The issue is fixed once third-party cookies are enabled on Safari, which is not an option on iOS.

How can I fix this problem?

One potential solution I'm considering is overriding fetch to use native http client (i.e., an instance of HTTP from @ionic-native/http). It seems modifying http clients is a possibility (e.g., according to this conversation) but I'm not sure how to achieve that.


Solution

  • Changing the HTTP plumbing sounds like a really bad idea - time cost, mainly - unless you just absolutely have to use sessions/cookies...If you don't, read on.

    as noted here regarding pouchDB Security, I tried using pouchdb-authentication when it was actively maintained and went another route due to multiple issues (I don't recall specifics, it was 6 years ago).

    Do note the last commit to pouchdb-authentication seems to be 3 years ago. Although inactivity is not an negative indicator on the surface - a project may have simply reached a solid conclusion - installing pouchdb-authentication yields this

    found 6 vulnerabilities (2 moderate, 3 high, 1 critical)
    

    That plus the lack of love given to plugin over the last few years makes for a dangerous technical debt to add for a new project.

    If possible simply send credentials using the auth option when creating (or opening) a remote database, e.g.

    const credentials = { username: 'foo', passwd: 'bar' };
    this.remote = new PouchDB(couchDBurl, { auth: credentials }); 
    

    I don't recall why but I wrote code that is in essence what follows below, and have reused it ad nauseum because it just works with the fetch option

    const user = { name: 'foo', pass: 'bar' };
    const options = { fetch: function (url, opts) {
        opts.headers.set('Authorization', 'Basic ' + window.btoa(user.name+':'+user.pass));
        return PouchDB.fetch(url, opts);
      }
    };
    
    this.remote = new PouchDB(couchDBurl, options); 
    

    I believe I chose this approach due to the nature of my authentication workflow discussed in the first link of this answer.