Sync Gateway Cookie Auth with Cordova

I have been trying to get Sync Gateway authentication integrated into my app for a couple of weeks now. I thought I had finally rounded the bend, but now I have one more thing biting me in the ass.

I have implemented custom auth as a REST API, that uses the Sync Gateway ADMIN API as recommended. Since the client is a Cordova app, I can’t set cookies from the server, so I am generating a JWT Token with the session info, and returning in the response body to the client which is decoding the token to get the session ID.

On the client (based on some forums) I had thought I could set the cookie header in PouchDB, but now I am getting - Refused to set unsafe header “Cookie”. Seems like you can’t set a cookie header in Chrome (possibly other browsers) in an XHR request.

I am using Angular on the client, but this doesn’t seem to just be an Angular issue. Has anybody got Sync Gateway authentication using cookies working with a Cordova application?

FYI - I am using PouchDB on the client, not Couchbase Lite since my app also runs in a browser.

Found my own answer. You can create cookies with JavaScript in the Cordova client, they just won’t be preserved between app instances, so you have to create them manually when the application starts up.

For PouchDB authentication, you can call the session endpoint and this should set the SyncGateway cookie for future requests. Then, you can kick off replication and all requests will use that cookie.

Let us know if you have any other questions regarding this setup.

James

Hey @jamiltz, thank you for helping me on the forums. Originally, I was working with the cookie from Sync Gateway trying both avenues of authenticating directly to Sync Gateway, and then using my custom REST API with the ADMIN API.

The problem (as I understand it from research not a hands-on test) is that Cordova seems to have very spotty support for supporting cookies set from a server. It works on some versions of IOS, reportedly only the very latest version of Android 5.1. After researching on many forums, it seems on an XHR request, if cookies are set from the server Cordova just strips them out.

http://justbuildsomething.com/cordova-and-express-session/
https://cordovablogsblogs.wordpress.com/2015/03/08/handling-cookies-in-phonegapcordova/

It would be really nice to see future versions of Sync Gateway support more options for authentication including JsonWebTokens or just standard headers. The limitation of only being able to use a cookie creates problems like this.

@chrismbeckett Sounds like my setup is the same as yours and I’ve also ran into this problem. I use a custom REST API, JWT and the session endpoint over the admin API to create the cookie.

res.header('Authorization', 'Bearer ' + token);
res.cookie(body.cookie_name, body.session_id, cookieOpts);

req.jsend.success({
                token: token,
                session: body,
                user: user
            });

PouchDB won’t replicate when running on the device as the requests don’t have the cookie set. I’m in the process of trying to work around the issue now as I have the cookie data in the returned session property. It’s been a real pain.

@chrismbeckett could you explain your solution in more detail as I can’t seem to get it to work. Thanks!

Nevermind, I finally managed to get the pouchdb replication to sync gateway in cordova / xwalk working after days of trial and error. Basically return the cookie details as part of the json login response, so in my case that’s in the session property in the code snippet above… then add that cookie info to your pouchdb opts in a custom header that won’t complain about being set:

var opts = {
                since: 0,
                include_docs: false,
                attachments: false,
                crossDomain: true,
                withCredentials: true,
                skipSetup: true,
                ajax: {
                    headers: {
                        'Authorization': SessionService.getAuthorizationHeader(),
                        'ProxyCookie': SessionService.getCookieHeader()
                    }
                };

Note you can also add the ProxyCookie to all outgoing $http requests via a custom interceptor if you want consistency, but it’s not needed.

You need to replicate to a custom REST endpoint that will proxy sync gateway. I’m using node and express, and I setup my cors on this to accept the ProxyCookie header among the other ones like Authorization etc.

My api/sync route looks something like this:

'use strict';

var express = require('express'),
    router = express.Router(),
    config = require('module/config'),
    httpProxy = require('http-proxy'),
    syncProxy = httpProxy.createProxyServer({
        target: config.SG_CONFIG.PUBLIC_ENDPOINT,
        xfwd: true
    });

syncProxy.on('proxyReq', function (proxyReq, req, res, options) {
    // Cookie workaround for cordova / xwalk
    var proxycookie = req.headers.proxycookie;
    if (proxycookie) {
        proxyReq.setHeader('Cookie', proxycookie);
    }
});

syncProxy.on('error', function (e) {
    console.log('\n\nsyncProxy error', e);
});

router.all('*', function (req, res) {
    syncProxy.web(req, res);
});

module.exports.router = router;

It’s really important to define this root BEFORE the body parser if you are using it, this tripped me up for awhile.

// Add cookie parser middleware
router.use(cookieParser());

// Add sync / proxy route before body parser middleware
router.use('/sync', require('./sync').router);

// Add json body parser middleware
router.use(bodyParser.urlencoded({'extended': 'true'}));
router.use(bodyParser.json());
router.use(bodyParser.json({type: 'application/vnd.api+json'}));

Finally in my sync gateway config I setup my cors headers like so:
"headers": ["Accept", "Authorization", "Content-Type", "Origin", "Referer", "X-CSRF-Token"],

I think that was it. I hope this saves someone else some time, as I’ve lost a few days trying to get cookies working in cordova / xwalk for authenticating sync gateway replication. I really wish it supported JWT.

Thanks a lot for posting your detailed solution. We ran into te same issue some time ago and revert to basic authentication till we would have time to spend on getting sessions working. But with information you sent it looks like we should get it up and runnning quickly. Thanks again! We will post back here some more information if we had to make some adjustments