{"id":7526,"date":"2019-08-11T22:46:19","date_gmt":"2019-08-12T05:46:19","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=7526"},"modified":"2025-06-13T20:52:24","modified_gmt":"2025-06-14T03:52:24","slug":"custom-authentication-with-couchbase-mobile","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/custom-authentication-with-couchbase-mobile\/","title":{"rendered":"Custom Authentication with Couchbase Mobile"},"content":{"rendered":"<h2>Custom Authentication with Couchbase Mobile<\/h2>\n<p>Couchbase Mobile extends Couchbase to the edge, securely managing and syncing data from any cloud to every mobile device. Couchbase Mobile features an embedded database \u2013 Couchbase Lite \u2013 with SQL and full-text search for JSON, built-in peer-to-peer synchronization, and end-to-end security from cloud to edge.<\/p>\n<p>Couchbase Mobile also features a secure web gateway \u2013 Sync Gateway \u2013 that enables data access and synchronization over the web and supports multiple <a href=\"https:\/\/docs.couchbase.com\/sync-gateway\/current\/authentication.html\">authentication methods<\/a>. One of these methods is custom authentication where an App Server handles the authentication with an external system.<\/p>\n<p>This blog post will guide you through the custom authentication flow with examples of how to implement the App Server code and the mobile app code. An <a href=\"https:\/\/www.openldap.org\/\">OpenLDAP<\/a> server is used in this example, but the flow applies to any external authentication provider.<\/p>\n<p>The example App Server is a simple node.js application and the mobile app code samples use the <a href=\"https:\/\/docs.couchbase.com\/couchbase-lite\/2.5\/java.html\">Couchbase Lite Android SDK<\/a>.<\/p>\n<h2>Prerequisites<\/h2>\n<p>This blog assumes familiarity with Couchbase Server, Sync Gateway, and Couchbase Lite.<\/p>\n<p>You will need an operational Sync Gateway 2.5 &amp; Couchbase Server EE 6.x installation. If needed, the following links can get you up and running quickly:<\/p>\n<ol>\n<li><a href=\"https:\/\/docs.couchbase.com\/sync-gateway\/2.5\/getting-started.html#install-couchbase-server\">Install Couchbase Server<\/a><\/li>\n<li><a href=\"https:\/\/docs.couchbase.com\/sync-gateway\/2.5\/getting-started.html\">Install Sync Gateway<\/a><\/li>\n<li><a href=\"https:\/\/docs.couchbase.com\/sync-gateway\/2.5\/getting-started.html#configure-sync-gateway\">Configure Sync Gateway<\/a><\/li>\n<\/ol>\n<p>All code from this blog is available in the following Git repository: <a href=\"https:\/\/github.com\/dugbonsai\/sg-custom-auth\">https:\/\/github.com\/dugbonsai\/sg-custom-auth<\/a><\/p>\n<h2>Custom Authentication Flow<\/h2>\n<p>The following diagram shows an example of custom authentication.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-7527\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2019\/08\/SG-Custom-Auth-Flow.jpg\" alt=\"\" width=\"2048\" height=\"1152\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/08\/SG-Custom-Auth-Flow.jpg 2048w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/08\/SG-Custom-Auth-Flow-300x169.jpg 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/08\/SG-Custom-Auth-Flow-1024x576.jpg 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/08\/SG-Custom-Auth-Flow-768x432.jpg 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/08\/SG-Custom-Auth-Flow-1536x864.jpg 1536w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/08\/SG-Custom-Auth-Flow-20x11.jpg 20w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/08\/SG-Custom-Auth-Flow-1320x743.jpg 1320w\" sizes=\"auto, (max-width: 2048px) 100vw, 2048px\" \/><\/p>\n<ol>\n<li>The mobile app user attempts to log in with their credentials through a REST interface exposed by the App Server.<\/li>\n<li>The App Server authenticates the user against an OpenLDAP Server.<\/li>\n<li>If the user is not authenticated, the user is returned to the login UI.<\/li>\n<li>If the user is authenticated, the App Server gets the user information from Sync Gateway through a REST interface.<\/li>\n<li>If the user does exist in Sync Gateway skip to step 8.<\/li>\n<li>If the user does not exist in Sync Gateway, the App Server creates a new user in Sync Gateway through a REST interface.<\/li>\n<li>If the user was not created in Sync Gateway, the App Server returns an error and the user is returned to the login UI.<\/li>\n<li>If the user was created in Sync Gateway, the App Server creates a new session for the user in Sync Gateway through a REST interface.<\/li>\n<li>If the session was not created in Sync Gateway, the App Server returns an error and the user is returned to the login UI.<\/li>\n<li>If the session was created in Sync Gateway, the App Server returns the session ID.<\/li>\n<li>The mobile app stores the session ID and creates a Couchbase Lite replicator using the session ID.<\/li>\n<li>If replication fails due to an expired session in Sync Gateway, the user is returned to the login UI.<\/li>\n<\/ol>\n<h2>OpenLDAP Configuration<\/h2>\n<p>If you already have an LDAP server configured you can skip this section. If you do not have an LDAP server configured, <a href=\"https:\/\/www.techrepublic.com\/article\/how-to-install-openldap-on-ubuntu-18-04\/\">these instructions will walk you through configuring OpenLDAP on Ubuntu 18.04<\/a>.<\/p>\n<ol>\n<li>Create an LDIF file (<a href=\"https:\/\/github.com\/dugbonsai\/sg-custom-auth\/blob\/master\/ldap_data.ldif\">ldap_data.ldif<\/a>) with information to populate the LDAP database (<a href=\"https:\/\/en.wikipedia.org\/wiki\/LDAP_Data_Interchange_Format\">click here for more details on LDIF files<\/a>). The instructions for configuring OpenLDAP above also contain instructions for creating the LDIF file to populate the LDAP database. In this example, user mobileuser (starting on line 13) will be used when authenticating from the mobile app.<\/li>\n<\/ol>\n<pre class=\"lang:default decode:true\">dn: ou=People,dc=example,dc=com\r\nobjectClass: organizationalUnit\r\nou: People\r\n\r\ndn: ou=Groups,dc=example,dc=com\r\nobjectClass: organizationalUnit\r\nou: Groups\r\ndn: cn=department,ou=Groups,dc=example,dc=com\r\nobjectClass: posixGroup\r\ncn: subgroup\r\ngidNumber: 5000\r\n\r\ndn: uid=mobileuser,ou=People,dc=example,dc=com\r\nobjectClass: inetOrgPerson\r\nobjectClass: posixAccount\r\nobjectClass: shadowAccount\r\nuid: mobileuser\r\nsn: User\r\ngivenName: Mobile\r\ncn: Mobile User\r\ndisplayName: mobileuser\r\nuidNumber: 10000\r\ngidNumber: 5000\r\nuserPassword: password\r\ngecos: Mobile User\r\nloginShell: \/bin\/bash\r\nhomeDirectory: \/home\/mobileuser<\/pre>\n<ol start=\"2\">\n<li>Add the initial data to the OpenLDAP database:<\/li>\n<\/ol>\n<pre class=\"lang:default decode:true\">$ ldapadd -x -D cn=admin,dc=example,dc=com -W -f ldap_data.ldif<\/pre>\n<ol start=\"3\">\n<li>Test the setup by searching for mobileuser in the OpenLDAP directory:<\/li>\n<\/ol>\n<pre class=\"lang:default decode:true \">$ ldapsearch -x -LLL -b dc=example,dc=com 'uid=mobileuser'<\/pre>\n<p>You will see the information for mobileuser:<\/p>\n<pre class=\"lang:default decode:true \">dn: uid=mobileuser,ou=People,dc=example,dc=com\r\nobjectClass: inetOrgPerson\r\nobjectClass: posixAccount\r\nobjectClass: shadowAccount\r\nuid: mobileuser\r\nsn: User\r\ngivenName: Mobile\r\ncn: Mobile User\r\ndisplayName: mobileuser\r\nuidNumber: 10000\r\ngidNumber: 5000\r\ngecos: Mobile User\r\nloginShell: \/bin\/bash\r\nhomeDirectory: \/home\/mobileuser<\/pre>\n<h2><span style=\"color: #343e47;font-family: Lato, 'Helvetica Neue', Helvetica, Arial, sans-serif;font-size: 60px\">App Server Implementation<\/span><\/h2>\n<p>The App Server is implemented as a node.js application. The full App Server code is available in <a href=\"https:\/\/github.com\/dugbonsai\/sg-custom-auth\/blob\/master\/auth.js\">auth.js<\/a> in the following Git repository: <a href=\"https:\/\/github.com\/dugbonsai\/sg-custom-auth\">sg-custom-auth<\/a>. The App Server uses the <a href=\"https:\/\/www.npmjs.com\/package\/passport-ldapauth\">passport-ldapauth package<\/a> for LDAP authentication. The following code snippets highlight the call to authenticate against the OpenLDAP server and the Sync Gateway REST API calls.<\/p>\n<p>The App Server must handle calls to POST \/login. This endpoint is called from the mobile app with the user credentials stored in the request body in username and password. The App Server uses these credentials to authenticate against the OpenLDAP server.<\/p>\n<p>The value of searchBase must match the domain components defined in your LDAP server. dc=example,dc=com was used above so the same values are used here (line 12).<\/p>\n<pre class=\"lang:default decode:true\">var express = require('express'),\r\n     passport = require('passport'),\r\n     bodyParser = require('body-parser'),\r\n     LdapStrategy = require('passport-ldapauth'),\r\n     curl = require('curl-request');\r\n\r\nvar syncGatewayEndpoint = 'https:\/\/&lt;Sync Gateway Host&gt;:4985\/&lt;db&gt;';\r\nvar app = express();\r\nvar OPTS = {\r\n     server: {\r\n          url: 'ldap:\/\/&lt;OpenLDAP Host&gt;:389',\r\n          searchBase: 'dc=example,dc=com',&amp;nbsp; \/\/ MUST match LDAP directory\r\n          searchFilter: '(uid={{username}})'\r\n     }\r\n};\r\n\r\npassport.use(new LdapStrategy(OPTS));\r\napp.use(bodyParser.json());\r\napp.use(bodyParser.urlencoded({extended: false}));\r\napp.use(passport.initialize());\r\n\r\napp.post('\/login', passport.authenticate('ldapauth', {session: false}), function(req, res) {\r\n     \/\/ user successfully authenticated against LDAP\r\n}<\/pre>\n<p>The following steps will be executed if the user is authenticated.<\/p>\n<h4>Get user information from Sync Gateway<\/h4>\n<p>Get user information from Sync Gateway by calling <a href=\"https:\/\/docs.couchbase.com\/sync-gateway\/2.5\/admin-rest-api.html#\/user\">GET \/{db}\/_user\/{name}<\/a>. If the user exists in Sync Gateway, the response code is 200. If the user does not exist in Sync Gateway, the response code is 404.<\/p>\n<pre class=\"lang:default decode:true\">getUser = new(curl);\r\ngetUser.setHeaders(['Content-Type: application\/json'])\r\n     .get(syncGatewayEndpoint + '\/_user\/' + req.body.username)\r\n     .then(({statusCode, body, headers}) =&gt; {\r\n          if (statusCode == 404) {\r\n               \/\/ status == 404: user does not exist\r\n          } else if (statusCode == 200) {\r\n               \/\/ status == 200: user exists\r\n          }\r\n     })<\/pre>\n<h4>If the user does not exist in Sync Gateway, create a new user<\/h4>\n<p>Create a new user in Sync Gateway by calling <a href=\"https:\/\/docs.couchbase.com\/sync-gateway\/2.5\/admin-rest-api.html#\/user\">POST \/{db}\/_user\/<\/a>. If the user was successfully created in Sync gateway, the response code is 201.<\/p>\n<pre class=\"lang:default decode:true \">postUser = new(curl);\r\npostUser.setHeaders(['Content-Type: application\/json'])\r\n     .setBody('{\"name\": \"' + req.body.username + '\",\"password\": \"' + req.body.password + '\"}')\r\n     .post(syncGatewayEndpoint + '\/_user\/')\r\n     .then(({statusCode, body, headers}) =&gt; {\r\n          if (statusCode == 201) {\r\n               \/\/ status == 201: success\r\n          } else {\r\n               \/\/ user could not be created\r\n          }\r\n     })<\/pre>\n<h4>Create a session for the user in Sync Gateway<\/h4>\n<p>Create a session for the user in Sync Gateway by calling <a href=\"https:\/\/docs.couchbase.com\/sync-gateway\/2.5\/admin-rest-api.html#\/session\">POST \/{db}\/_session<\/a>. In this example, the session will expire after 30 minutes. If the session was successfully created in Sync Gateway, the response code is 200. The JSON response contains the following values:<\/p>\n<p><strong>session_id<\/strong>: the ID for the new session. This will be used by the mobile app for authentication with Sync Gateway.<\/p>\n<p><strong>expires<\/strong>: timestamp when the session expires. This is not used in the mobile app.<\/p>\n<p><strong>cookie_name<\/strong>: name of the session cookie. This is not used in the mobile app.<\/p>\n<pre class=\"lang:default decode:true \">resBody = {statusCode: 200};\r\npostSession = new(curl);\r\npostSession.setHeaders(['Content-Type: application\/json'])\r\n     .setBody('{\"name\": \"' + request.body.username + '\",\"ttl\": 1800}')\r\n     .post(syncGatewayEndpoint + '\/_session')\r\n     .then(({statusCode, body, headers}) =&gt; {\r\n          if (statusCode == 200) {\r\n               \/\/ status == 200: success\r\n               resBody.session_id = body.session_id;\r\n               resBody.expires = body.expires;\r\n               resBody.cookie_name = body.cookie_name;\r\n\r\n               \/\/ send success response back to client\r\n               response.send(JSON.stringify(resBody));\r\n          } else {\r\n               \/\/ session could not be created\r\n          }\r\n     })<\/pre>\n<h2><span style=\"color: #343e47;font-family: Lato, 'Helvetica Neue', Helvetica, Arial, sans-serif;font-size: 60px\">Testing Authentication<\/span><\/h2>\n<p>To test the authentication from the App Server, start it using the following command:<\/p>\n<pre class=\"lang:default decode:true \">$ node auth.js<\/pre>\n<p>After it starts you will see the following:<\/p>\n<pre class=\"lang:default decode:true \">Listening on port 8080<\/pre>\n<p>You can test the app server using a simple curl command as follows (or Postman, etc.):<\/p>\n<pre class=\"lang:default decode:true\">$ curl -d \"username=mobileuser&amp;password=password\" -X POST https:\/\/&lt;AppServer host&gt;:8080\/login<\/pre>\n<p>You will see output similar to the following:<\/p>\n<pre class=\"lang:default decode:true \">{\"statusCode\":200,\"session_id\":\"c149012eaa8d0cf15b1b4110cf0a2fec259ef726\",\"expires\":\"2019-08-01T13:47:56.311076773Z\",\"cookie_name\":\"SyncGatewaySession\"}<\/pre>\n<p>If the user does not exist in LDAP, the response will be:<\/p>\n<pre class=\"lang:default decode:true \">Unauthorized<\/pre>\n<p>The output from the App Server will look like this:<\/p>\n<pre class=\"lang:default decode:true \">mobileuser has been authenticated with LDAP\r\ncreating user mobileuser in Sync Gateway\r\nuser mobileuser created in Sync Gateway\r\ncreate session for user mobileuser\r\ncreated session for mobileuser<\/pre>\n<h2><span style=\"color: #343e47;font-family: Lato, 'Helvetica Neue', Helvetica, Arial, sans-serif;font-size: 60px\">Mobile App Implementation<\/span><\/h2>\n<p>All that is left to do is make the appropriate calls from the Mobile App to the App Server and Sync Gateway. The mobile app uses the <a href=\"https:\/\/developer.android.com\/training\/volley\">Volley framework<\/a> to make the REST call to the App Server. The following code snippets highlight the call to the App Server and the Couchbase Lite code to authenticate using the session_id.<\/p>\n<h4>Authenticate mobile user<\/h4>\n<p>Authenticate user with App Server by calling POST \/login\/<\/p>\n<pre class=\"lang:default decode:true \">JSONObject reqBody = new JSONObject();\r\nreqBody.put(\"username\", &lt;user supplied username&gt;);\r\nreqBody.put(\"password\", &lt;user supplied password&gt;);\r\n\r\nString url = &lt;App Server host&gt;:8080\/login;\r\nRequestQueue queue = Volley.newRequestQueue(&lt;context&gt;);\r\nJsonRequest&lt;JSONObject&gt; jsonRequest = new JsonObjectRequest(\r\n     Request.Method.POST,\r\n     url,\r\n     reqBody,\r\n     new Response.Listener&lt;JSONObject&gt;() {\r\n          @Override\r\n          public void onResponse(JSONObject response) {\r\n      \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ get session_id from response\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 try {\r\n     \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 String sessionID = response.getString(\"session_id\");\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Store session_id\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 } catch (JSONException je) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Handle exception\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n          }\r\n     },\r\n     new Response.ErrorListener() {\r\n          @Override\r\n    \u00a0\u00a0\u00a0\u00a0\u00a0 public void onErrorResponse(VolleyError error) {\r\n     \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ authentication failed\r\n          }\r\n     });\r\n\r\nqueue.add(jsonRequest);<\/pre>\n<h4>Create one-shot replication<\/h4>\n<p>Create one-shot replication using saved session_id (line 13) and re-authenticate if Sync Gateway session has expired.<\/p>\n<pre class=\"lang:default decode:true \">String syncGatewayEndpoint = \"ws:\/\/&lt;Sync Gateway Host&gt;:4984\/{db}\";\r\nURI url = null;\r\ntry {\r\n     url = new URI(mSyncGatewayEndpoint);\r\n} catch (URISyntaxException e) {\r\n     e.printStackTrace();\r\n     return;\r\n}\r\n\r\nReplicatorConfiguration config = new ReplicatorConfiguration(database, new URLEndpoint(url));\r\nconfig.setReplicatorType(ReplicatorConfiguration.ReplicatorType.PUSH_AND_PULL);\r\nconfig.setContinuous(false);\r\nconfig.setAuthenticator(new SessionAuthenticator(sessionID));\r\n\r\nReplicator replicator = new Replicator(config);\r\nreplicator.addChangeListener(new ReplicatorChangeListener() {\r\n     @Override\r\n\u00a0\u00a0\u00a0\u00a0 public void changed(ReplicatorChange change) {\r\n          CouchbaseLiteException error = change.getStatus().getError();\r\n          if (error != null) {\r\n               if (error.getCode() == 10401) {\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \r\n                    \/\/ session expired; re-authenticate\r\n               }\r\n          }\u00a0\r\n\r\n          ...\r\n     }\r\n});\r\nreplicator.start();<\/pre>\n<h2>What\u2019s Next<\/h2>\n<p>If you&#8217;re new to Couchbase, take advantage of our free, online training available at <a href=\"https:\/\/learn.couchbase.com\/\">https:\/\/learn.couchbase.com<\/a> to learn more.<\/p>\n<p>More <a href=\"https:\/\/www.couchbase.com\/blog\/mobile-tutorials\/\">mobile tutorials<\/a> can be found on the <a href=\"https:\/\/docs.couchbase.com\/tutorials\/index.html\">Couchbase Tutorials web page<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Custom Authentication with Couchbase Mobile Couchbase Mobile extends Couchbase to the edge, securely managing and syncing data from any cloud to every mobile device. Couchbase Mobile features an embedded database \u2013 Couchbase Lite \u2013 with SQL and full-text search for [&hellip;]<\/p>\n","protected":false},"author":1352,"featured_media":7527,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[2370,1815,1810,1822,1813,2366],"tags":[],"ppma_author":[9091],"class_list":["post-7526","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-android","category-best-practices-and-tutorials","category-couchbase-mobile","category-node-js","category-security","category-sync-gateway"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.8 (Yoast SEO v25.8) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Custom Authentication with Couchbase Mobile - The Couchbase Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/custom-authentication-with-couchbase-mobile\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Custom Authentication with Couchbase Mobile\" \/>\n<meta property=\"og:description\" content=\"Custom Authentication with Couchbase Mobile Couchbase Mobile extends Couchbase to the edge, securely managing and syncing data from any cloud to every mobile device. Couchbase Mobile features an embedded database \u2013 Couchbase Lite \u2013 with SQL and full-text search for [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/custom-authentication-with-couchbase-mobile\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2019-08-12T05:46:19+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-14T03:52:24+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/08\/SG-Custom-Auth-Flow.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"2048\" \/>\n\t<meta property=\"og:image:height\" content=\"1152\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Douglas Bonser, Principal Solution Engineer, Couchbase\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Douglas Bonser, Principal Solution Engineer, Couchbase\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"6 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/custom-authentication-with-couchbase-mobile\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/custom-authentication-with-couchbase-mobile\/\"},\"author\":{\"name\":\"Douglas Bonser, Principal Solution Engineer, Couchbase\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/7fdd6feab8e25100caf61bb7836ee0ff\"},\"headline\":\"Custom Authentication with Couchbase Mobile\",\"datePublished\":\"2019-08-12T05:46:19+00:00\",\"dateModified\":\"2025-06-14T03:52:24+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/custom-authentication-with-couchbase-mobile\/\"},\"wordCount\":1100,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/custom-authentication-with-couchbase-mobile\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/08\/SG-Custom-Auth-Flow.jpg\",\"articleSection\":[\"Android\",\"Best Practices and Tutorials\",\"Couchbase Mobile\",\"Node.js\",\"Security\",\"Sync Gateway\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/custom-authentication-with-couchbase-mobile\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/custom-authentication-with-couchbase-mobile\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/custom-authentication-with-couchbase-mobile\/\",\"name\":\"Custom Authentication with Couchbase Mobile - The Couchbase Blog\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/custom-authentication-with-couchbase-mobile\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/custom-authentication-with-couchbase-mobile\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/08\/SG-Custom-Auth-Flow.jpg\",\"datePublished\":\"2019-08-12T05:46:19+00:00\",\"dateModified\":\"2025-06-14T03:52:24+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/custom-authentication-with-couchbase-mobile\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/custom-authentication-with-couchbase-mobile\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/custom-authentication-with-couchbase-mobile\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/08\/SG-Custom-Auth-Flow.jpg\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/08\/SG-Custom-Auth-Flow.jpg\",\"width\":2048,\"height\":1152},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/custom-authentication-with-couchbase-mobile\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Custom Authentication with Couchbase Mobile\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/7fdd6feab8e25100caf61bb7836ee0ff\",\"name\":\"Douglas Bonser, Principal Solution Engineer, Couchbase\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/e922810e11bd43dd211ba0ee960f9738\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/68f7547e24c39852e700940d8209edf75f6b9cd64ba057ce1e11313d9230ab84?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/68f7547e24c39852e700940d8209edf75f6b9cd64ba057ce1e11313d9230ab84?s=96&d=mm&r=g\",\"caption\":\"Douglas Bonser, Principal Solution Engineer, Couchbase\"},\"description\":\"Douglas Bonser is a Principal Solutions Engineer at Couchbase and has been working in IT and technology since 1991. He is based in the Dallas\/Ft. Worth area.\",\"url\":\"https:\/\/www.couchbase.com\/blog\/author\/douglas-bonsercouchbase-com\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Custom Authentication with Couchbase Mobile - The Couchbase Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/custom-authentication-with-couchbase-mobile\/","og_locale":"en_US","og_type":"article","og_title":"Custom Authentication with Couchbase Mobile","og_description":"Custom Authentication with Couchbase Mobile Couchbase Mobile extends Couchbase to the edge, securely managing and syncing data from any cloud to every mobile device. Couchbase Mobile features an embedded database \u2013 Couchbase Lite \u2013 with SQL and full-text search for [&hellip;]","og_url":"https:\/\/www.couchbase.com\/blog\/custom-authentication-with-couchbase-mobile\/","og_site_name":"The Couchbase Blog","article_published_time":"2019-08-12T05:46:19+00:00","article_modified_time":"2025-06-14T03:52:24+00:00","og_image":[{"width":2048,"height":1152,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/08\/SG-Custom-Auth-Flow.jpg","type":"image\/jpeg"}],"author":"Douglas Bonser, Principal Solution Engineer, Couchbase","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Douglas Bonser, Principal Solution Engineer, Couchbase","Est. reading time":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/custom-authentication-with-couchbase-mobile\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/custom-authentication-with-couchbase-mobile\/"},"author":{"name":"Douglas Bonser, Principal Solution Engineer, Couchbase","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/7fdd6feab8e25100caf61bb7836ee0ff"},"headline":"Custom Authentication with Couchbase Mobile","datePublished":"2019-08-12T05:46:19+00:00","dateModified":"2025-06-14T03:52:24+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/custom-authentication-with-couchbase-mobile\/"},"wordCount":1100,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/custom-authentication-with-couchbase-mobile\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/08\/SG-Custom-Auth-Flow.jpg","articleSection":["Android","Best Practices and Tutorials","Couchbase Mobile","Node.js","Security","Sync Gateway"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/custom-authentication-with-couchbase-mobile\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/custom-authentication-with-couchbase-mobile\/","url":"https:\/\/www.couchbase.com\/blog\/custom-authentication-with-couchbase-mobile\/","name":"Custom Authentication with Couchbase Mobile - The Couchbase Blog","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/custom-authentication-with-couchbase-mobile\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/custom-authentication-with-couchbase-mobile\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/08\/SG-Custom-Auth-Flow.jpg","datePublished":"2019-08-12T05:46:19+00:00","dateModified":"2025-06-14T03:52:24+00:00","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/custom-authentication-with-couchbase-mobile\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/custom-authentication-with-couchbase-mobile\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/custom-authentication-with-couchbase-mobile\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/08\/SG-Custom-Auth-Flow.jpg","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/08\/SG-Custom-Auth-Flow.jpg","width":2048,"height":1152},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/custom-authentication-with-couchbase-mobile\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Custom Authentication with Couchbase Mobile"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"The Couchbase Blog","description":"Couchbase, the NoSQL Database","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"The Couchbase Blog","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/7fdd6feab8e25100caf61bb7836ee0ff","name":"Douglas Bonser, Principal Solution Engineer, Couchbase","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/e922810e11bd43dd211ba0ee960f9738","url":"https:\/\/secure.gravatar.com\/avatar\/68f7547e24c39852e700940d8209edf75f6b9cd64ba057ce1e11313d9230ab84?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/68f7547e24c39852e700940d8209edf75f6b9cd64ba057ce1e11313d9230ab84?s=96&d=mm&r=g","caption":"Douglas Bonser, Principal Solution Engineer, Couchbase"},"description":"Douglas Bonser is a Principal Solutions Engineer at Couchbase and has been working in IT and technology since 1991. He is based in the Dallas\/Ft. Worth area.","url":"https:\/\/www.couchbase.com\/blog\/author\/douglas-bonsercouchbase-com\/"}]}},"authors":[{"term_id":9091,"user_id":1352,"is_guest":0,"slug":"douglas-bonsercouchbase-com","display_name":"Douglas Bonser, Principal Solution Engineer, Couchbase","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/68f7547e24c39852e700940d8209edf75f6b9cd64ba057ce1e11313d9230ab84?s=96&d=mm&r=g","author_category":"","last_name":"Bonser, Principal Solution Engineer, Couchbase","first_name":"Douglas","job_title":"","user_url":"","description":"Douglas Bonser is a Principal Solutions Engineer at Couchbase and has been working in IT and technology since 1991. He is based in the Dallas\/Ft. Worth area."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/7526","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/users\/1352"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/comments?post=7526"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/7526\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media\/7527"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media?parent=7526"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/categories?post=7526"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/tags?post=7526"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=7526"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}