Hi, I’m brand new “refugee” from MongoDb Realm fiasco, looking to migrate to Couchbase Lite for offline first, “end-user centric” app on mobile and desktop via .net maui. I’m using the Realms migration example app (GitHub - couchbaselabs/cbl-template-app-maui-todo: Conversion Example of .NET Maui app from MongoDb Atlas Device SDK to Couchbase Mobile) to get started. I’ve got my Capella app and service all configured following the mds in the app solution, and have green lights and happiness on the web Capella side of things. The cbl-template-app-maui-todo solution is also up and running and pointing to the correct endpont for the capella app (is that right terminology?) but I get a “Not Authorized” error when I try and login in to the db (line 33 of the AuthenticationService.cs file in RealmTodo/Services). I followed all the configuration steps and and have checked the example user credentials twice, so I think I’m missing a step to add either of the “demo users” to so they can be authorized to the app? It’s very similiar to mongodb setup but different enough I’d appreciate any help. Thanks - and please forgive me if this isn’t the right forum channel and be kind enough to redirect.
Also, would someone be kind enough to clarify the difference between Capella and CBL? Is Capella the web service to configure apps and endpoints and CBL the client side library it uses?
Thanks for the quick reply not sure I understand you recommendation as this step is right in the middle of the initial authentication process . Is it reasonable to expect subsequent CRUD calls to work if the user isn’t even authorized to connect? Not being ungrateful just don’t follow recommendation.
@DavidGerding Hello and good day - I wrote the code and did the videos on all the various repos. A few things:
- Are you sure that it’s line 33 that is coming back with the error? How the code works is it strips out the endpoint from the full site URL because the IsUrlReachable is making sure that the network is available and the hostname looks up in DNS and the root of the App Services site answers. So line 14 removes the endpoint name from the full path so we can check it:
var checkUrl = httpsUrl.Replace("/tasks", "/");
This is because every App Services Endpoint has a separate set of users for authentication and I don’t know how many other endpoints a user might create. The root of the site should always answer back with a generic set of JSON data without needing a username/password because it’s like a heart beat, for example:
https://your_app_service_site_code.apps.cloud.couchbase.com:4984/
When I go to my personal free account with my WITHOUT the endpoint the URL in Google Chrome I get:
{"couchdb":"Welcome","vendor":{"name":"Couchbase Sync Gateway","version":"3.2"},"version":"Couchbase Sync Gateway/3.2.0(514;51025c6) EE","persistent_config":true}
You should get the same thing. So that’s the first thing to check is to put a break point in on line
33, check the urlString value by copying the value and putting in your browser. If you put it in your browser and it doesn’t work at all or asks for a username and password then something is wrong or configured different within your App Services configuration.
If that works, then the IsUrlReachable method should also work. Now there is one other possible issue: Google Cloud
If you are using Google Cloud specifically the port that App Services runs on isn’t the standard 4984/4985 and you would need to make very sure you cut and paste the proper value from the Connection tab in Couchbase Capella into the capellaConfig.json file exactly how it is stated from the Connect tab. If you read over my code in the Authentication Endpoint you will see that I’m very specifically only replacing wss: if it already exists in the string. When you cut-and-paste the value from a Google Cloud instance it would already be https: so that code should basically just return the URL from the config file.
If you could let me know what you get back from there I can further better help you troubleshoot the issue.
- So naming of the various products:
Couchbase Capella = Couchbase’s Cloud Service
App Services = Couchbase Capella’s App Services which allows you to sync between a mobile database and the cloud.
App Services Endpoint - an individual endpoint for syncing information from one or several collections. This is a security boundary (security of users, configuration, etc is per endpoint).
CBL = Couchbase Lite. Couchbase Lite is the mobile database that runs on device, such as a mobile phone, IoT Device, etc.
Couchbase Mobile = Couchbase Capella App Service + Couchbase Lite.
Let me know if this helps.
Thanks
Aaron LaBeau
Accessing the endpoint url (without a path) does not need authentication.
If your app is accessing a url without a path, that does need authentication - that is not the correct url. In the sample, this comes from your capellaConfig.json and is modified (protocol https is used, “task” is removed). cbl-template-app-maui-todo/RealmTodo/capellaConfig.json at main · couchbaselabs/cbl-template-app-maui-todo · GitHub
% curl https://umjxalhf5gjjhoiy.apps.cloud.couchbase.com:4984/
{“couchdb”:“Welcome”,“vendor”:{“name”:“Couchbase Sync Gateway”,“version”:“3.2”},“version”:“Couchbase Sync Gateway/3.2.0(514;51025c6) EE”,“persistent_config”:true}
Capella is the name of the hosted system in which the backend (Couchbase Server and Sync Gateway) are deployed for you. CBL is an SDK that gets installed onto a mobile device to provide offline first functionality and sync to the backend (capella or on prem, or even P2P to another device). Since I work on CBL I prefer to think of Capella as “one of the servers CBL can talk to” rather than CBL being “a client side library for Capella”.
Thanks for the helpful reply.
The urlString that is being passed in as a parameter and returning the unauthorized response at line 33 is:
https://[redacted].apps.cloud.couchbase.com:4984/lf
“lf” is the named endpoint, and seems to be the cause of the problem.
When I paste the url with the lf endpoint name, the browser interactively asks for authentication. When provided with the correct demo1@example.com user credential, it authenticated.
If I remove the lf endpoint from the url and then browse to that, it works and returns successful connect json.
So the problem is sendin the lf endpoint extension. Did I misconfigure the cappela json, meaning should it have the lf endpoint on the url - or should I add code to remove the lf endpoint for this step in the existing demo? Since I’ll be basing all my code on this implementation eventually, I’d love to get the capella json configured correctly and/or figure out the best “longer term solution”.
Thanks!!
Dave G
I can confirm that manualy removing the “/lf” endpoint designation from the call to IsUrlReachable seems to have fixed the problem. Can you confirm if this makes sense before I move ahead with making a more real persistence service tier from this example? And thanks!
Dave G
The endpoint is supposed to be /tasks and it is supposed ro be removed by the replace(). How does it get to be /lf ?
Hi,
Sorry for the delayed reply and appreciate your response. Very, very new to Couchbase. As I was configuring the app in Capella for the first time, if did not follow the example guidance to name the endpoint tasks. I named it /lf because I imagined the endpoint was an “application endpoint” and not a collection endpoint.
The “lf” endpoint has a configured bucket and linked scope of data, which does follow the example, and I have successfully had the app example running when using this endpoint naming.
I’m assuming that since this was working, that I am correct that the lf endpoint is an “app configuration scope”, rather than an entity or type “scope” like in REST. Otherwise, I wouldn’t have expected it to work at all. Again, I was able to create, update and delete documents in the data scope (of type “Item”, from the example) with this endpoint configuration.
If you have the time, I’d appreciate clarification from anyone reading this (including mreiche) that clears up the requirement / pattern of endpoint naming conventon in couchbaselite in relation to document or scope names.
Thanks, Dave G
Since the path of the endpointUrl must be /task, I’m not sure why that is configurable in the example. Perhaps if the example were to be used as a basis for something else, different paths could be used.
Thanx for the example. It works fine on Android using either emulator or device. No issues there. However I get a “403 forbidden error” (line 33) when running Windows machine. Any idea why? I turned off my vpn app and firewall to no avail.
Thank you.
Can you show the code and the url?
It’s usually better to start a new “Topic” in forums.couchbase.com as posting on an existing topic makes it look “stale”.
Wow, that’s a fast reply.
Config:
“endpointUrl”: “wss://…apps.cloud.couchbase.com:4984/tasks”,
“capellaUrl”: “https://cloud.capella.com”
I haven’t touch any of this code. This is the original from github repo.
using RealmTodo.Models;
namespace RealmTodo.Services;
public class AuthenticationService : IAuthenticationService
{
public async Task<User?> Login(string username, string password, CouchbaseAppConfig config)
{
if (config == null)
{
throw new InvalidOperationException(“Must call CouchbaseService.init prior to calling Login”);
}
var httpsUrl = config.EndpointUrl.Replace("wss:", "https:");
var checkUrl = httpsUrl.Replace("/tasks", "/");
if (!await IsUrlReachable(checkUrl))
{
throw new InvalidOperationException("Unable to connect to the server. Please check your network connection.");
}
var httpClient = GetHttpClient();
var encoding = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes($"{username}:{password}"));
httpClient.DefaultRequestHeaders.Add("Authorization", $"Basic {encoding}");
httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
var response = await httpClient.GetAsync($"{httpsUrl}/");
return response.IsSuccessStatusCode ? new User(username, password) : null;
}
private static async Task<bool> IsUrlReachable(string urlString)
{
try
{
var httpClient = GetHttpClient();
var response = await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, urlString));
return response.IsSuccessStatusCode;
}
catch (Exception)
{
return false;
}
}
private static HttpClient GetHttpClient()
{
var httpClient = new HttpClient
{
Timeout = TimeSpan.FromSeconds(5)
};
return httpClient;
}
}
403 Forbidden indicates the server does not allow access to the URL - so check closely that the correct URL is being accessed, and also check that the url is accessible (by using curl as outlined above).
If this you still have issues, @biozal might be able to help.
Added this line: httpClient.DefaultRequestHeaders.Add(“User-Agent”,“Win64”);
to both IsUrlReachable and Login methods and it worked.