User authentication/document best practices


#1

Hi All,

What I want to accomplish is:

  • The user is using his iOS device and there is Couchbase Lite installed.
  • When the app is up and running the first time, the client device will pull the public data through synch gateway. The client app will use the synch gateway username/plain password over HTTP connection. (The data is not that sensitive as the app can be downloaded by anyone and data is open anyways.)
  • User will have to login using Facebook/Email (Persona) and create the user on the Couchbase Server the first time to have user specific data created for him.
  • User will create his own data (Account information, preferences, etc…) as documents in Couchbase Lite locally on the device. For the document created, email address can be used to identify the document for him. For Eg: AccountInfo001 { “doctype”:“account”, “userID”:"abc@ahahah.com", …}
  • If user is logged in, this data will be push synched to Couchbase Server in the background.

Now my questions/assumptions are:

  • Is the above setup is OK for a mobile app which can work offline/online?
  • The user can work offline to update his account data stored locally in Couchbase Lite. And once logged in, the data is push synched to Couchbase Server. So login will help him only to push his account info to the server. Nothing else. In this case, can we store the token locally and user never have to login again?
  • Can the user register using Facebook once and then login using email (Persona)? Or it should always the same method of authentication?

Thx a lot
CK


#2

It sounds reasonable.

In step 2 when pulling the public data, there’s no need for any auth. You can enable guest access in Sync Gateway and make some documents available via the guest account.

An actual user account isn’t a document. To create an account in SG you’ll need some server-side component to call the SG admin API. However, it’s a known idiom to have a per-user document storing “profile” metadata about that user; you just need to lock it down so only that user can create or modify it.

In this case, can we store the token locally and user never have to login again?

Not quite sure what you mean by that. Your app is welcome to store the user’s password permanently, but that only applies to password-based auth. If you want to use Facebook or Persona, the tokens for those protocols expire and have to be renewed from the Facebook or Persona servers. Also, for any session-based auth, SG’s session cookies expire after 24 hours of inactivity.


#3

Hi Jens,

Thanks for reply. So this is what I got from your comments:

  • Pull public data with guest account on the SG.
  • Authenticate using Facebook or Persona against SG and then create one document locally per user to keep profile metadata on the CouchBase Lite on device.
  • Then SG can then synch this profile document to the server automatically.
  • Whenever user logins after the token expiration using Facebook or Persona, the local profile document can be pushed/updated on the server thru SG automatically.

But, I am not sure what you meant by locking it only for that user? Are you suggesting to use pessimistic locking before updates? Can you give an example please?

I am new to Couchbase, so appreciate your feedback. Thanks again.

Thx
CK


#4

Sorry, I didn’t mean “locking” in that sense. I meant to restrict write access to that document so only the user it’s about can create or modify it. This is pretty easy to enforce in a sync function; something like

if (doc.type == "profile")
    requireUser(doc.username);

#5

Thanks a lot for that.


#6

I’m a little confused on this. I have a database where no documents are shared between device users. That means I have no Guest user. So here is my flow:

User uses restful webservice to create an account
Webservice creates a user record in a database accessible by admin
Webservice creates a user on the sync gateway

User uses restful webservice to login to account
Webservice does oauth against user’s username and password in the admin access store and says its okay
Webservice authenticates user against sync gateway and returns session information
User then starts syncing data the user creates and only that data through some sort of restriction set using the sync function?

Profit

So what limits documents to only the specific user that created/has access to it?
Does each user have their own channel and this limits the user to it? Maybe it is in the requireUser() command that you specify?
Do I have to create a doc.username in every document that I create or is there metadata of that user that can then restrict users to those documents?
How during registration do I give the user access to the document that the admin creates to store the users data?


#7

I am not expert. But instead of crating a record on the central DB first,I am planning to register the user using Facebook-Persona through synch gateway. See this: http://developer.couchbase.com/mobile/develop/guides/sync-gateway/administering-sync-gateway/authenticating-users/index.html

Then, I will create an account document for the user on the local device and push it to the server thru synch.
For each document created for the user, I will add the “owner”:"sjjsj@djdjdj.com"

And put restriction with requireUser(doc.owner) on synch gateway.

That way I will push all docs created locally on device to the server, and when accessing user docs, there will be a need to authenticate first. and then assuming local device will pull only the documents, it has access with requireUser. (I think this is the only way this can be modeled not to define a channel for each user to push things up to each user. User has to pull using the API.)

Please someone correct me If I am wrong!


#8

requireUser in the documentation only seems to restrict update access. How do you restrict syncing data from the server to the device that is not owned by that user?


#9

Oops, sorry!

To restrict read access to a single user, define a channel specific to that user, give the user access to it (add it to the admin_channels property in their user record), and assign the doc to that channel.

if (doc.type == "profile") {
    requireUser(doc.username);
    channel("user-" + doc.username);
}

#10

@jens,

Can you clarify on session expiration? Lets say if an app does a sync multiple times a day, will the session expiration be extended?


#11

Yes, I believe the session is extended every time the client authenticates. (Originally it wasn’t, but this was requested about a year ago and I’m pretty sure I remember Andy Reslan implementing it.)


#12

So does sync gateway respond back with a new expiration timestamp?


#13

I don’t know … @march44, do you know?


#14

@agillette

This is the pull request for the change, with a description of the behaviour. If the session is extended then an updated cookie is returned to the client.

Andy


#15

Thanks @andy for the info.


#16

@jens

Hello, we are authenticating the user through a custom service and creating a user on couchbase server through syncgateway. The password for that user is hashed and stored on the couchbase and also on couchbaselite since it syncs the record.

The app should be able to work offline and hence need to read the stored user document on CBLite. The password is hashed here and is there an easier way to validate the password the user enters against the hashed password, will bcrypt work? Or is there a way CbLite can authenticate users using locally stored credentials?


#17

@preethi.minti Please try not to resurrect old threads to ask new questions - posting a new topic will help us and other users find the answers quickly.


#18

Couchbase Lite doesn’t have any support for that. It’s not very secure since anyone with access to the device can read all users’ data in the database, and they could locally overwrite any users’s hashed password in the document and replace it with one they know the password to. (It’s also considered insecure to expose hashed passwords outside the security domain they’re created on.)

I don’t understand why you’re asking how to check the password against the hash. Since it’s your code that creates the hash on the server side, you should know how to verify it.

If you really want to securely store multiple users’ data on one device, give each user their own database and encrypt each database with a password chosen by that user.


#19

The reason I ask is, we need to be able to support offline authentication. When we create a user on couchbase server, it hashes the password with bcrypt and stored as passwordhash_bcrypt. It is not application code that hashes the password.

Does this user record get pushed to CBLite?

If the device is offline, how do we validate the username and password and let the user in? please let me know if this question is clear. We need to be able to store the credentials locally. And all our devices are encrypted at the OS level. But we do not still want to store clear text password. The users of the device are employees of the organization and we do not want anyone to see the password.


#20

Hello,

I was told not to mix topics so I thought I had to post my questions in the forums that are related to the topic

Are you suggesting that I create a new topic for all my questions? I thought related questions go to the same threads.

Please let me know where I can post my questions. Thank you all for the help!!!