AspNetCore.Identity.CosmosDb 9.0.1

dotnet add package AspNetCore.Identity.CosmosDb --version 9.0.1                
NuGet\Install-Package AspNetCore.Identity.CosmosDb -Version 9.0.1                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="AspNetCore.Identity.CosmosDb" Version="9.0.1" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add AspNetCore.Identity.CosmosDb --version 9.0.1                
#r "nuget: AspNetCore.Identity.CosmosDb, 9.0.1"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install AspNetCore.Identity.CosmosDb as a Cake Addin
#addin nuget:?package=AspNetCore.Identity.CosmosDb&version=9.0.1

// Install AspNetCore.Identity.CosmosDb as a Cake Tool
#tool nuget:?package=AspNetCore.Identity.CosmosDb&version=9.0.1                

Cosmos DB Provider for ASP.NET Core Identity

CodeQL Net 9 Tests (192) NuGet

This is a Cosmos DB implementation of an Identity provider that uses the "Entity Framework Core, Azure Cosmos DB Provider". Please let us know if any changes need to be made to this document. Thank you!

Projects that use this library

If you would like your project here, send us a note or log an issue. Thanks!

Version 9 compatibility with version 8 databases

Cosmos DB Entity Framework verion 9 had important changes that required important changes to this project. Listed below are the changes addressed in this project.

The id property no longer contains the discriminator by default

This project requires the "Descriminator" to be part of the ID value like this:

IdentityUser|07c09eac-8815-43d3-9141-30876ef0e465

However EF 9 does not include the descrimintator by default. To include it the following code builder.HasDiscriminatorInJsonIds(); is added to the OnModelCreating method of the CosmosIdentityDbContext class:

       protected override void OnModelCreating(ModelBuilder builder)
       {

           // dotnet/efcore#35224
           // New behavior for Cosmos DB EF is new.  For backward compatibility,
           // we need to add the following line to the OnModelCreating method.
           builder.HasDiscriminatorInJsonIds();
           .
           .
           .
       }

The discriminator property is now named $type instead of Discriminator

When using EF 9 to read a database created with EF 8 or earlier, there may not be any error thrown. Instead, the read will return no records, which can be mystifying. The reason is the Discriminator field name has changed from "Descriminator" to "$type". Consequently, EF 9 does not find the descriminator value.

This was fixed in the project by adding the following code builder.HasEmbeddedDiscriminatorName("Discriminator") to the OnModelCreating method of the CosmosIdentityDbContext class. Also note in the following code the field _backwardCompatibility.

        protected override void OnModelCreating(ModelBuilder builder)
        {
            .
            .
            .
            if (_backwardCompatibility)
            {
                builder.HasEmbeddedDiscriminatorName("Discriminator");
            }
        }

To enable backward compatibility with the "Discriminator," set the backwardCompatibility field of the context constructor to true (note: default is false). Here is an example:

var options = new DbContextOptionsBuilder<CosmosIdentityDbContext>();
options.UseCosmos(connectionString, databaseName);
using var dbContext = new ApplicationDbContext(tempBuilder.Options, true); // True is set for backward compatibility

HasIndex now throws instead of being ignored

There are two ways to handle this: (1) Remove the index definitions on the entities, or (2), add the following code to suppress the exception in the `OnConfiguring' method like this:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.ConfigureWarnings(w => w.Ignore(CosmosEventId.SyncNotSupported));
}

Updates to unit tests

A new unit test was added to test backward compatibility. The tests use two different Cosmos DB accounts. It is suggested to use "serverless" accounts to keep costs down.

The "secrets" file now needs two database connection strings like this:

{
  "CosmosIdentityDbName": "localtests", // Both test projects use this database name.
  "ConnectionStrings": {
    // Database account used for backward compatibility tests.
    "ApplicationDbContextConnection2": "AccountEndpoint=[YOUR CONNECTION STRING HERE]",
    // Used for EF version 9 and above tests.
    "ApplicationDbContextConnection": "AccountEndpoint=[YOUR CONNECTION STRING HERE]"
  }
}

Upgrading from version 2.x to 8.x

When upgrading to version 8 from 2, you will need to make two changes to your project:

The old way of creating the Database Context looked like this:

public class ApplicationDbContext : CosmosIdentityDbContext<IdentityUser, IdentityRole>

The new way is like this (with 'string' added):

public class ApplicationDbContext : CosmosIdentityDbContext<IdentityUser, IdentityRole, string>

Next, in your Program.cs or Startup.cs files, change from this:

 builder.Services.AddCosmosIdentity<ApplicationDbContext, IdentityUser, IdentityRole>

To this (with 'string' added):

 builder.Services.AddCosmosIdentity<ApplicationDbContext, IdentityUser, IdentityRole, string>

Installation

Tip: This package uses seven (7) "containers." If the RU throughput for your Cosmos Account is configured at the "container" level, this can require your Cosmos DB Account to require a higher minimum RU.

Sharing Throughput

To keep costs down, consider sharing throughput at the database level as described here in the documentation. This allows you to, for example, set the RU at the database to be 1,000 RU, then have all containers within that database share those RU's.

Autoscale

Next, set the RU to "autoscale." According to documentation, "Autoscale provisioned throughput in Azure Cosmos DB allows you to scale the throughput (RU/s) of your database or container automatically and instantly." This will allow your database to scale down and up as needed, thus reducing your monthly costs further.

Nuget Package

Add the following NuGet package to your project:

PM> Install-Package AspNetCore.Identity.CosmosDb

Create an Azure Cosmos DB account - either the free, serverless or dedicated instance. For testing and development purposes it is recommended to use a free account. See documentation to help choose which type of Cosmos account is best for you.

Set your configuration settings with the connection string and database name. Below is an example of a secrets.json file:

{
  "SetupCosmosDb": "true", // Importat: Remove this after first run.
  "CosmosIdentityDbName": "YourDabatabaseName",
  "ConnectionStrings": {
    "ApplicationDbContextConnection": "THE CONNECTION STRING TO YOUR COSMOS ACCOUNT"
  }
}

Update Database Context

Modify the database context to inherit from the CosmosIdentityDbContext like this:

using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;

namespace AspNetCore.Identity.CosmosDb.Example.Data
{
    public class ApplicationDbContext : CosmosIdentityDbContext<IdentityUser, IdentityRole, string>
    {
        public ApplicationDbContext(DbContextOptions dbContextOptions)
          : base(dbContextOptions) { }
    }
}

Modify Program.cs or Startup.cs File

After the "secrets" have been set, the next task is to modify your project's startup file. For Asp.net 6 and higher that might be the Project.cs file. For other projects it might be your Startup.cs.

You will likely need to add these usings:

using AspNetCore.Identity.CosmosDb;
using AspNetCore.Identity.CosmosDb.Containers;
using AspNetCore.Identity.CosmosDb.Extensions;

Next, the configuration variables need to be retrieved. Add the following to your startup file:

// The Cosmos connection string
var connectionString = builder.Configuration.GetConnectionString("ApplicationDbContextConnection");

// Name of the Cosmos database to use
var cosmosIdentityDbName = builder.Configuration.GetValue<string>("CosmosIdentityDbName");

// If this is set, the Cosmos identity provider will:
// 1. Create the database if it does not already exist.
// 2. Create the required containers if they do not already exist.
// IMPORTANT: Remove this setting if after first run. It will improve startup performance.
var setupCosmosDb = builder.Configuration.GetValue<string>("SetupCosmosDb");

Add this code if you want the provider to create the database and required containers:

// If the following is set, it will create the Cosmos database and
//  required containers.
if (bool.TryParse(setupCosmosDb, out var setup) && setup)
{
    var builder1 = new DbContextOptionsBuilder<ApplicationDbContext>();
    builder1.UseCosmos(connectionString, cosmosIdentityDbName);

    using (var dbContext = new ApplicationDbContext(builder1.Options))
    {
        dbContext.Database.EnsureCreated();
    }
}

Now add the database context in your startup file like this:

builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseCosmos(connectionString: connectionString, databaseName: cosmosIdentityDbName));

Follow that up with the identity provider. Here is an example:

builder.Services.AddCosmosIdentity<ApplicationDbContext, IdentityUser, IdentityRole, string>(
      options => options.SignIn.RequireConfirmedAccount = true // Always a good idea :)
    )
    .AddDefaultUI() // Use this if Identity Scaffolding is in use
    .AddDefaultTokenProviders();

Adding Google or Microsoft OAuth providers

This library works with external OAuth providers, and below is an example of how we implement this.

Begin by adding these two NuGet packages to your project:

Then add the code below to your Project.cs file.

// Example of adding OAuth Providers
// Add Google if keys are present
var googleClientId = Configuration["Authentication_Google_ClientId"];
var googleClientSecret = Configuration["Authentication_Google_ClientSecret"];

// If Google ID and secret are both found, then add the provider.
if (!string.IsNullOrEmpty(googleClientId) && !string.IsNullOrEmpty(googleClientSecret))
{
    builder.Services.AddAuthentication().AddGoogle(options =>
    {
        options.ClientId = googleClientId;
        options.ClientSecret = googleClientSecret;
    });
}

// Add Microsoft if keys are present
var microsoftClientId = Configuration["Authentication_Microsoft_ClientId"];
var microsoftClientSecret = Configuration["Authentication_Microsoft_ClientSecret"];

// If Microsoft ID and secret are both found, then add the provider.
if (!string.IsNullOrEmpty(microsoftClientId) && !string.IsNullOrEmpty(microsoftClientSecret))
{
    builder.Services.AddAuthentication().AddMicrosoftAccount(options =>
    {
        options.ClientId = microsoftClientId;
        options.ClientSecret = microsoftClientSecret;
    });
}

To learn more about external OAuth providers, please see the Microsoft documentation on this subject.

Complete Startup File Example

The above instructions showed how to modify the startup file to make use of this provider. Sometimes it is easier to see the end result rather than peicemeal. Here is an example Asp.Net 6 Project.cs file configured to work with this provider, scaffolded identity web pages, and the SendGrid email provider:

An example web application is also available.

Supported LINQ Operators User and Role Stores

Both the user and role stores now support queries via LINQ using Entity Framework. Here is an example:

var userResults = userManager.Users.Where(u => u.Email.StartsWith("bob"));
var roleResults = roleManager.Roles.Where (r => r.Name.Contains("water"));

For a list of supported LINQ operations, please see the "Supported LINQ Operations" documentation for more details.

Help Find Bugs

Find a bug? Let us know by contacting us via NuGet or submit a bug report on our GitHub issues section. Thank you in advance!

Changelog

This change log notes major changes beyond routine documentation and NuGet dependency updates.

v9.0.1.0

Removed the sample application included here as it was out of date. In its place, an ongoing project (Cosmos CMS) that uses this package as an example.

v9.0.0.3

  • Backward campatibility added for databases created EF version 8 or earlier.
  • Added unit tests for backward compatibility testing.

v9.0.0.1

  • Updated for .Net 9, and version 9 of the Entity Framework.

v8.0.0.3

  • Now supports generic keys.
  • Applied patch for issue #14.

v8.0.0.1

  • Now built for .Net 8, and removed support for 6 and 7.
  • Updated NuGet packages to latest releases.

v2.1.1

  • Added support for .Net 6 and .Net 7.

v2.0.20

  • Addressing bug #9, implemented interfaces IUserAuthenticatorKeyStore and IUserTwoFactorRecoveryCodeStore to support two factor authentication. Example website updated to demonstrate capability with QR code generation.

v1.0.6

  • Introduced support for IUserLoginStore<TUser> in User Store

v1.0.5

  • Introduced support for IUserPhoneNumberStore<TUser> in User Store

v1.0.4

  • Introduced support for IUserEmailStore<TUser> in User Store

v2.0.0-alpha

  • Forked from source repository pierodetomi/efcore-identity-cosmos.
  • Refactored for .Net 6 LTS.
  • Added UserStore, RoleStore, UserManager and RoleManager unit tests.
  • Namespace changed to one more generic: AspNetCore.Identity.CosmosDb
  • Implemented IUserLockoutStore interface for UserStore

v2.0.1.0

  • Added example web project

v2.0.5.1

  • Implemented IQueryableUserStore and IQueryableRoleStore

Unit Test Instructions

To run the unit tests you will need two things: (1) A Cosmos DB Account, and (2) a connection string to that account. Here is an example of a secrets.json file created for the unit test project:

{
  "CosmosIdentityDbName" : "YOURDATABASENAME",
  "ConnectionStrings": {
    "ApplicationDbContextConnection": "AccountEndpoint=YOURCONNECTIONSTRING;"
  }
}

Choice of Cosmos DB Account Type

This implementation will work with the "Free" Cosmos DB tier. You can have one per account.

It also works the "serverless" and "provisioned" account types.

References

To learn more about Asp.Net Identity and items realted to this project, please see the following:

Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (3)

Showing the top 3 NuGet packages that depend on AspNetCore.Identity.CosmosDb:

Package Downloads
Cosmos.Cms.Common

This package contains all the common methods and objects used by the Cosmos CMS editor website, and by any website service the role of a publishing website.

Cosmos.Common

This package contains all the common methods and objects used by the Cosmos CMS editor website, and by any website service the role of a publishing website.

Brupper.AspNetCore.Identity

Package Description

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
9.0.1 0 1/21/2025
9.0.0.3 281 1/10/2025
9.0.0 512 12/6/2024
8.0.7 3,299 9/3/2024
8.0.6 2,665 5/29/2024
8.0.4 591 4/18/2024
8.0.3 865 3/12/2024
8.0.2 1,122 2/15/2024
8.0.1 1,446 1/12/2024
8.0.0 1,027 12/18/2023
8.0.0-rc.3 82 12/15/2023
2.1.4 7,492 1/30/2023
2.1.3 680 12/15/2022
2.1.2 502 11/16/2022
2.1.1 519 11/11/2022
2.0.22 412 11/9/2022
2.0.21 412 11/6/2022
2.0.20 1,308 10/27/2022
2.0.19-rc 162 10/26/2022
2.0.18 903 9/24/2022
2.0.17 421 9/5/2022
2.0.16 723 8/24/2022
2.0.15 487 8/13/2022
2.0.14 419 8/11/2022
2.0.13 459 8/8/2022
2.0.12 468 7/31/2022
2.0.11 472 7/23/2022
2.0.10 484 7/13/2022
2.0.9 457 7/12/2022
2.0.8 486 7/12/2022
2.0.7 465 7/8/2022
2.0.6 465 7/8/2022
2.0.5.1 470 7/6/2022
2.0.4 474 7/5/2022
2.0.3.3 469 7/4/2022
2.0.3.2 492 7/3/2022
2.0.3.1 491 7/3/2022
2.0.2.1 484 7/1/2022
2.0.1-alpha 198 6/30/2022
2.0.0-alpha 209 6/25/2022

Dependencies update.