I wanted to build authentication and cloud storage into my indie app, Remotime, and decided to go with Azure AAD B2C and Cosmos DB, simply because both of these products have a decent free tier to get you going and work with technologies that I'm familiar with. Unfortunately, both of these products are not as easy to get started with as, for example, google's Firebase set of products.
Getting started with AAD B2C has already been covered elsewhere, although I will mention briefly that if you want to have a more native auth experience, have a look at B2C ROPC policies for login and embedded MSAL for signup / registration.
In this post, we'll cover the basics of accessing Cosmos DB directly from your Xamarin app using an access token provided by an azure function. The access token is needed because you don't want to be storing your Cosmos DB access keys within the app package. Instead, you can store your access keys securely in Azure Key Vault, and grant access exclusively to an azure function app. This function app will then return a limited lifespan resource token to the xamarin app with specific permissions to access the Cosmos DB.
Unfortunately, Microsoft's own documentation and most blog posts covering the topic, though helpful, are still stuck on the older v2 Cosmos SDK. Here I'll link to an example using the latest v3 Cosmos SDK to both get the access token from a serverless function, as well as from the xamarin app itself.
If you want to skip directly to the code, you can find the github project here.
This won't be a step-by-step guide - there's plenty out there on the web to get you started. I will instead highlight some of the issues I ran into, and what I did to solve them.
Domain Model Structure
Cosmos is a document DB, which is quite different to the SQL Server relational data store that I was used to. It takes a while to get out of the table-per-model / primary / foreign key relations mindset. Here's a good introduction.
Advantages for me:
- flexible document db data structures (no table migrations) - schema agnostic
- global distribution: my app has a global market (well, that's the plan anyway)
- high performance and elastic scalability
- Linq / SQL query language support
- free tier of 400 RU/s
So for me, I settled on a single container / collection called "UserData" that will store all the domain models. My C# class to store all data to Cosmos looks like this. This CosmosDocument has an "id" property which maps to the id of the domain model (must be lowercase for the json serialization), a "Type" property to query by type, a "UserId" property to use as a partition key (see more about that here), and finally a "Model" property of type T - where T is any of my domain models.
The Resource Token Provider
You can find the core logic for providing a Cosmos DB access token here. This is a simple example, that accepts a user id (or a JWT access token), and returns a single read-write permission back to the caller. For a much more comprehensive example for return multiple permissions based on scopes defined in the JWT access token, have a look here.
The example app covers accessing either a function running on your local machine, or in the azure cloud. Have a look at the readme for local / cloud configurations in the appsettings.json files.
The Xamarin Client App
Quick tip. Install the CosmosDB emulator , and run the local file explorer. There you'll find up to date sample app downloads on how to access Cosmos DB.
I did have an issue connecting to the local emulator from the android emulator, but thankfully a recent SDK update solved that, by allowing the app to bypass SSL on calls to the emulator.
Also remember to add startup parameters to the emulator to AllowNetworkAccess
And a special mention for working with Dates. For me, all my domain model date properties automatically convert to UTC in the setters, and the UI layer has converters to show local time.
Using the sample app, you should be able to configure access to both the local function and Cosmos DB Emulator, or an Azure Function App and/or Azure CosmosDB.
As an aside, the v3 SDK does provide the ability to perform bulk updates (configurable via the CosmosClientOptions class when creating the CosmosClient). As of this writing though, it seems that this option does not work in conjunction with a resource token, as SDK calls are rejected by a Forbidden 403 response. I'm still digging into why that is...
For mobile apps though, it may be a good idea to steer clear of bulk update operations, as this will bottleneck you RU/s capacity to a single request, which could impact requests from other app instances calling to your data store.
Hopefully this should get you down the road quicker than it did me :)
It's still a work in progress, so subscribe to the repo for updates.
Top comments (0)