CPE.DapperIdentity.Stores 0.9.0

dotnet add package CPE.DapperIdentity.Stores --version 0.9.0
                    
NuGet\Install-Package CPE.DapperIdentity.Stores -Version 0.9.0
                    
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="CPE.DapperIdentity.Stores" Version="0.9.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="CPE.DapperIdentity.Stores" Version="0.9.0" />
                    
Directory.Packages.props
<PackageReference Include="CPE.DapperIdentity.Stores" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add CPE.DapperIdentity.Stores --version 0.9.0
                    
#r "nuget: CPE.DapperIdentity.Stores, 0.9.0"
                    
#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.
#:package CPE.DapperIdentity.Stores@0.9.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=CPE.DapperIdentity.Stores&version=0.9.0
                    
Install as a Cake Addin
#tool nuget:?package=CPE.DapperIdentity.Stores&version=0.9.0
                    
Install as a Cake Tool

CPE.DapperIdentity

ASP.NET Core Identity with the user and role stores backed by Dapper instead of Entity Framework. Identity's own logic is unchanged; only the way it reads and writes the database is.

The stores use the generic repository from TheDapperRepository.

Packages

Five packages, one per dependency profile, always released together at the same version. Install only the ones your project needs; each pulls in what it depends on.

Package Use it in Brings in
CPE.DapperIdentity.Jwt.Server An ASP.NET Core API issuing JWTs Stores, Abstractions, JwtBearer
CPE.DapperIdentity.Jwt.Client A Blazor WebAssembly app calling that API Abstractions, Blazored.LocalStorage
CPE.DapperIdentity.Cookies.Server A Blazor Server / MVC app on cookie auth Stores, Abstractions
CPE.DapperIdentity.Stores Anything that only needs the Dapper stores Abstractions, Dapper
CPE.DapperIdentity.Abstractions Shared contracts and wire models nothing

All five target net8.0 and net10.0. Namespaces match the package ids (CPE.DapperIdentity.Stores, CPE.DapperIdentity.Jwt.Client, ...). The Add... registration methods live in Microsoft.Extensions.DependencyInjection, so Program.cs needs no extra using.

Database

The tables the stores expect are defined in two scripts shipped inside CPE.DapperIdentity.Stores, under sql/ in the package: mysql.txt (MySQL / MariaDB) and Sqlite.txt. Run the one for your database before first use.

The stores open connections through TheDapperRepository, so register a connection factory first:

using DapperRepository;

builder.Services.AddDbConnectionInstantiatorForRepositories<MySqlConnection>(connectionString);

JWT: the API (CPE.DapperIdentity.Jwt.Server)

Configuration

  "JwtTokenSettings": {
    "ValidIssuer": "ExampleIssuer",
    "ValidAudience": "ExampleAudience",
    "SymmetricSecurityKey": "keep-this-in-a-secret-store-not-in-appsettings",
    "JwtExpireSeconds": 900,
    "RefreshTokenLifeDays": 4
  }

Program.cs

builder.Services.AddDbConnectionInstantiatorForRepositories<MySqlConnection>(connectionString);
builder.Services.AddIAppSettings(new MyAppSettings());            // implements IAppSettings
builder.Services.AddTransient<IAuthEmailSender, MyEmailSender>(); // implements IAuthEmailSender
builder.Services.AddJwtIdentity(builder.Configuration);

AddJwtIdentity registers the stores, the token service, ASP.NET Core Identity, JWT bearer authentication, and JwtAuthController at /api/jwtauth with login, refresh, register, ForgotPassword and ResetPassword. It routes that one controller only.

IAppSettings.ApplicationName is the name used in account emails. IAuthEmailSender is how those emails are sent; the library never talks to an SMTP server itself.

Protect your own endpoints with [Authorize] / [Authorize(Roles = "...")] as usual.

The API emails users a link to set or reset their password. Two settings control it.

DapperIdentity:AppBaseUrl is required. The public address of the app that hosts the password-reset page, used to build that link. This is the address of your front end (for example your Blazor app), not of the API, even though it is set in the API's configuration. It differs per environment, so it belongs in appsettings.{Environment}.json or wherever your environment-specific settings live:

  "DapperIdentity": {
    "AppBaseUrl": "https://app.example.com"
  }

The API will not start without it, and says so by name. There is deliberately no fallback: the only one available would be the incoming request, and deriving the link from a request header lets anyone who can call the forgot-password endpoint choose where a real reset token is sent.

DapperIdentity:PasswordLinkLifetime is optional, default 24 hours. How long a link stays valid, as hours:minutes:seconds, between 15 minutes and 24 hours; anything else stops the API starting. It is a policy rather than a per-environment value, so set it once in appsettings.json if you set it at all:

  "DapperIdentity": {
    "PasswordLinkLifetime": "01:00:00"
  }

It can also be set in code. A Configure call made after AddJwtIdentity takes precedence over both the default and the configuration key, and the same range applies:

builder.Services.AddJwtIdentity(builder.Configuration);
builder.Services.Configure<DataProtectionTokenProviderOptions>(o => o.TokenLifespan = TimeSpan.FromMinutes(30));

The emails always quote the lifetime actually being enforced.

A persisted Data Protection key ring is required for this lifetime to hold. The token in the link is sealed with a Data Protection key rather than stored. If the key ring is ephemeral (on IIS, an app pool that does not load its user profile) every outstanding link dies at the next app-pool recycle, whatever lifetime is configured. On IIS, set the app pool's Load User Profile to True.

JWT: the Blazor WebAssembly client (CPE.DapperIdentity.Jwt.Client)

Configuration (wwwroot/appsettings.json)

  "AuthServer": {
    "Endpoint": "https://api.example.com"
  }

Program.cs

builder.Services.AddJwtWasmClient();

This registers JwtWasmClient (login, logout, token refresh, forgot and reset password, with the tokens kept in browser local storage), the lower-level JwtAuthClient it wraps, and HttpInterceptorService, which puts a valid bearer token on every outgoing HttpClient request and refreshes it shortly before it expires. Call RegisterEvent() on the interceptor once at startup and DisposeEvent() when you are done with it.

The library does not ship an AuthenticationStateProvider; your app keeps its own and passes its notify callback in:

@inject JwtWasmClient AuthClient

private async Task LoginClick()
{
    var result = await AuthClient.Login(new AuthRequest { Email = email, Password = password },
                                        myAuthStateProvider.NotifyUserAuthentication);
    if (result.Succeeded)
    {
        navManager.NavigateTo("/");
        return;
    }

    message = result.Failure switch
    {
        AuthFailure.InvalidCredentials => "That email and password don't match.",
        AuthFailure.ServerError        => "The server had a problem. Try again shortly.",
        _                              => "Login failed.",
    };
}

AuthResult is either tokens or a reason there are none; Succeeded tells you which. Network failures are not converted into a result and surface as exceptions, so wrap the call if the app can be offline.

Cookies: Blazor Server and MVC (CPE.DapperIdentity.Cookies.Server)

builder.Services.AddDbConnectionInstantiatorForRepositories<MySqlConnection>(connectionString);
builder.Services.AddDapperIdentityWithCustomCookies(TimeSpan.FromMinutes(30));

AddDapperIdentityWithCustomCookies registers the stores, ASP.NET Core Identity and cookie authentication, with the cookie lifetime you pass (sliding by default). No UI is included. Sign-in requires a confirmed email by default; pass requireConfirmedEmail: false if your app does not send confirmation mail.

To use Microsoft's Identity UI pages instead, call AddDapperIdentityWithVanillaUIAndDefaults and scaffold the pages you need. This package does not reference Microsoft.AspNetCore.Identity.UI or call AddDefaultUI(), so the pages are the ones you scaffold. Scaffolding asks for a DbContext; create an empty one, and delete it afterwards. Then alias the user type at the top of each scaffolded page's .cshtml.cs and of _LoginPartial.cshtml:

using IdentityUser = CPE.DapperIdentity.Stores.Models.CustomIdentityUser;

AddIdentityControllers adds a small IdentityController at /Identity/{action} for form-post login, logout and email confirmation without the default UI. Signing in has to be an HTTP POST so the cookie can be set:

<form action="Identity/Login" method="post">
    <input name="name" type="text" />
    <input name="password" type="password" />
    <input type="submit" />
</form>

Versioning

Every package in this repo carries the same version, set once in Directory.Build.props. The 0.x line means the API can still change between minor versions; read the release notes before upgrading.

License

MIT.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  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.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on CPE.DapperIdentity.Stores:

Package Downloads
CPE.DapperIdentity.Cookies.Server

Cookie authentication for ASP.NET Core and Blazor Server apps on the CPE.DapperIdentity stores, with opt-in account and identity controllers. For JWT APIs use CPE.DapperIdentity.Jwt.Server instead.

CPE.DapperIdentity.Jwt.Server

JWT bearer authentication for ASP.NET Core APIs on the CPE.DapperIdentity stores: token issue and refresh, registration, and a rate-limited password-reset flow whose links are built from configuration, never from the request.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.9.0 0 9/19/2026