For a phonegap app that I’m working on, I have developed an app server that is responsible for handling two-factor authentication instead of the traditional username/password combination. For 1st time users, I want it to also create user account documents on couchbase server that will not contain username and password, but will contain other authentication data. Then when the user logs in again, I want the app server to check couchbase server for the user account and if it’s valid, use sync gateway’s admin port to create a session as specified in the “Custom (Indirect) Authentication” documentation. During the sync gateway session, the user can CRUD documents.
I’ve read almost all of the documentation for couchbase lite REST API, sync gateway, and couchbase server. But I need some guidance on how I should setup sync gateway with couchbase server so that my app server can create user account documents while allowing authenticated users to CRUD documents through sync gateway. Here are two approaches that I’m considering:
- Use bucket shadowing so that the app server can create user account documents directly on couchbase server
- Have the app server use the admin port to sync gateway to create user account documents
I’m open to other architectural ideas as well.
We recommend using the REST API/Admin REST API in favour of bucket shadowing.
You can create documents, sessions and users on the admin port of Sync Gateway.
For custom auth, your app server can handle that as well and login/signup users via SG (see slides).
Thanks for the suggestion. The data that I want to store for a user is different from sync gateway’s _user. I want to create a custom user document and store it in couchbase because I don’t need password. I’m using two-factor authentication instead. How would I go about doing that? Should I use a different bucket that my app server has access to?
You can create custom user documents just like any other document and have a type property on it like
If you need to use the sync functions apis (channel, access, roles), you’ll still need to create a corresponding sync gateway user.
Would it be possible to have a bit more detail on the use case? Using basic auth on the admin rest api to signup/login users is currently the preferred way to plug in other auth systems (oauth, 2 factor auth…).
Here are more details:
The two-factor authentication calls a provided phone number for approval. Once approved, the app server will generate a jwt for the authenticated client app.
Here’s an approach that I want to run by you in regards to user creation and authentication:
- Using Admin REST API, create an admin account on sync gateway for app server. This will allow app server to create
- With the admin account, app server will use REST API to create
- Take the _id that is generated for the
profile and have app server use Admin REST API to create a _user with the proper role and channel assignments.
- On subsequent logins, the app server will use the
profile _id, which will also be the same value for
_user.name, to get a session info so that the client app can sync with sync gateway.
If you store the extra user metadata in SG documents, you’ll need to be careful that (a) clients can’t create or modify those documents, and (b) clients can’t read those documents if they contain any sensitive data. That would be done by your sync function.
You’d then use the SG admin REST API to manage the documents. (CRUD requests made by the admin API have ‘superuser’ access: in the sync function, calls like requireUser always succeed.)
I’m proposing creating two types of documents per user:
- profile - Using UUID for _id.
- _user - using prodile._id for the name.
I believe this way the user can make changes to their profile data, but not corrupt their _user document.
Sure, as long as you set up the sync function to disallow changes to the user document.
Is there a way in I can generate a _id value that is deterministic, like using a counter to create something like “u::0001”, with a sync gateway setup?
I suppose you can store your own counter externally and use it in the server-side software that creates those documents. (If you use your own Couchbase Bucket you can use the Increment operation to generate numbers this way.)
Just be aware that a client could (maliciously?) create a document with an ID in this format and cause collisions, unless you explicitly block that in the sync function.
Thanks @jens. This is something I leaning towards because it seems to be advocated as a way to creating documents in couchbase server, http://connect15.couchbase.com/agenda/three-things-need-know-document-data-modeling/.
In following through with you thought, I would create a set of “counter” documents in another bucket and have either app server or client app increment the counters when creating a deterministic _id.
Can you explain how the “superuser” access “bypasses” the requireUser or requireRole statements? Maybe provide some examples?
I just posted question that is similar what you mentioned here, using admin rest api on sync gateway
It’s pretty simple. If there’s no user associated with a document update (like if it’s made via the admin port or during a resync operation) then the requireXXX calls turn into no-ops, i.e. they always succeed.
So say I want the server to create a user profile on behalf of a user, I would use the admin port (ADMIN REST API) which bypasses requireUser. But if I want to give the user authorization to update their own profile, requireUser would do the check. Then any other sync gateway user would get an error response.
Right. So for example you could give the document the docID
profile-snej, then have the sync function recognize the
"profile-" prefix, split out the remainder as the user ID, and call
requireUser to ensure that only the user [or the admin port] can create/modify it.
(Or of course you could put the user ID in some custom property like
"user". The nice thing about putting it in the docID is it guarantees uniqueness, since you probably don’t want it to be possible to create multiple profiles for a user. It also makes it possible to look up the profile without a view query.)
Just a side note on your question regarding the deterministic incremental counting : fyi yes, there is a functionality in Couchbase server to implement incremental atomic count (see the counter() method) here:
Additionally, since as far as I understand you don’t need to rely on password management on the sync gateway, I’d suggest you might want to create the user in the sync gateway with a random hashed password as a ‘security best practice’, and then use the session token provided by the sync gateway for its respective auth.
BR / Thiago
Thanks for the tip @thiagoalencar.
There seems to be a discrepancy in the documentation for sync gateway session API. In the API reference, it states that the POST params should contain username and password, no mention of ttl. But in pub docs, it calls for username and ttl.
Which one is correct?
You’re right @agillette - that’s a bug in the API reference docs. That’s been fixed in the recent update of the docs - I’ll try to get those pushed live as soon as possible.
Just in case someone else crosses this thread, here you will find a sample implementation using python/Flask (python SDK 2.0), JWT, storing users in a Couchbase bucket with incremental count using N1QL: