PulseAuth.EntityFramework 1.0.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package PulseAuth.EntityFramework --version 1.0.0
                    
NuGet\Install-Package PulseAuth.EntityFramework -Version 1.0.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="PulseAuth.EntityFramework" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="PulseAuth.EntityFramework" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="PulseAuth.EntityFramework" />
                    
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 PulseAuth.EntityFramework --version 1.0.0
                    
#r "nuget: PulseAuth.EntityFramework, 1.0.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 PulseAuth.EntityFramework@1.0.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=PulseAuth.EntityFramework&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=PulseAuth.EntityFramework&version=1.0.0
                    
Install as a Cake Tool

PulseAuth Banner

PulseAuth

Free, open-source OAuth2 / OpenID Connect authorization server for ASP.NET Core.

PulseAuth is a lightweight alternative to Duende IdentityServer (formerly IdentityServer4) designed to be accessible, free, and easy to set up. It implements the core OAuth2 and OIDC flows on top of ASP.NET Core minimal APIs and integrates natively with ASP.NET Core Identity.


Packages

Package Description
PulseAuth Core OAuth2/OIDC server — endpoints, token service, in-memory stores
PulseAuth.Identity Connects PulseAuth to ASP.NET Core Identity (UserManager, SignInManager)
PulseAuth.EntityFramework EF Core persistent stores (clients, codes, refresh tokens)

Supported flows

  • Authorization Code + PKCE — secure for web apps, SPAs and mobile
  • Client Credentials — service-to-service authentication
  • Refresh Token — with optional rotation
  • Resource Owner Password — legacy, disabled by default per OAuth 2.1

OIDC endpoints

Endpoint URL
Discovery /.well-known/openid-configuration
JWKS /.well-known/jwks
Authorize /connect/authorize
Token /connect/token
UserInfo /connect/userinfo
Revocation /connect/revocation
End Session /connect/endsession

Quick start

1. Install

dotnet add package PulseAuth
dotnet add package PulseAuth.Identity
dotnet add package PulseAuth.EntityFramework   # optional, for production

2. Configure Program.cs

using PulseAuth.Constants;
using PulseAuth.Extensions;
using PulseAuth.Builders;
using PulseAuth.Helpers;
using PulseAuth.Models;

var builder = WebApplication.CreateBuilder(args);

// ── ASP.NET Core Identity ────────────────────────────────────────────────────
builder.Services
    .AddDbContext<ApplicationDbContext>(opts =>
        opts.UseSqlServer(builder.Configuration.GetConnectionString("Default")))
    .AddIdentity<ApplicationUser, IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>();

// ── PulseAuth ────────────────────────────────────────────────────────────────
builder.Services
    .AddPulseAuth(opts =>
    {
        opts.Issuer    = "https://auth.myapp.com";
        opts.LoginPath = "/Account/Login";
    })
    // Signing key — use AddDeveloperSigningCredential() for dev,
    // replace with a persistent key service for production
    .AddDeveloperSigningCredential()
    // In-memory clients — swap for .AddEntityFrameworkStores() in production
    .AddInMemoryClients(new[]
    {
        new Client
        {
            ClientId          = "my-spa",
            ClientName        = "My SPA",
            AllowedGrantTypes = GrantTypes.Code,
            RequirePkce       = true,
            AllowOfflineAccess = true,
            RedirectUris      = ["https://myapp.com/callback"],
            PostLogoutRedirectUris = ["https://myapp.com/"],
            AllowedScopes     = ["openid", "profile", "email", "offline_access"],
        },
        new Client
        {
            ClientId          = "api-service",
            ClientName        = "Backend API",
            ClientSecretHash  = ClientSecretHelper.HashSecret("super-secret"),
            AllowedGrantTypes = GrantTypes.ClientCredentialsOnly,
            AllowedScopes     = ["api"],
        },
    })
    // Connect to ASP.NET Core Identity for user management
    .AddIdentityUsers<ApplicationUser>()
    // Cookie auth for the interactive session
    .AddCookieAuthentication();

// ── External providers (optional) ────────────────────────────────────────────
builder.Services
    .AddPulseAuth()   // returns the existing builder
    .AddGoogle(
        clientId:     builder.Configuration["Auth:Google:ClientId"]!,
        clientSecret: builder.Configuration["Auth:Google:ClientSecret"]!)
    .AddFacebook(
        appId:     builder.Configuration["Auth:Facebook:AppId"]!,
        appSecret: builder.Configuration["Auth:Facebook:AppSecret"]!)
    .AddGitHub(
        clientId:     builder.Configuration["Auth:GitHub:ClientId"]!,
        clientSecret: builder.Configuration["Auth:GitHub:ClientSecret"]!)
    .AddMicrosoft(
        clientId:     builder.Configuration["Auth:Microsoft:ClientId"]!,
        clientSecret: builder.Configuration["Auth:Microsoft:ClientSecret"]!);

var app = builder.Build();

app.UseAuthentication();
app.UseAuthorization();

// Map all PulseAuth endpoints
app.MapPulseAuth();

app.Run();

3. (Production) Switch to persistent stores

builder.Services
    .AddPulseAuth(opts => opts.Issuer = "https://auth.myapp.com")
    .AddEntityFrameworkStores(opts =>
        opts.UseSqlServer(builder.Configuration.GetConnectionString("Default")))
    .AddIdentityUsers<ApplicationUser>();

Apply migrations:

dotnet ef migrations add InitPulseAuth --context PulseAuthDbContext
dotnet ef database update

Hashing client secrets

Never store plaintext secrets. Use the helper:

var (plain, hash) = ClientSecretHelper.GenerateAndHash();
Console.WriteLine($"Secret: {plain}");   // share this with the client
Console.WriteLine($"Hash:   {hash}");    // store this in the DB

// Or hash an existing secret:
string hash = ClientSecretHelper.HashSecret("my-secret");

Custom user store

Implement IUserAuthenticationService to use any user database:

public class MyUserService : IUserAuthenticationService
{
    public Task<UserInfo?> ValidateCredentialsAsync(string user, string pass, CancellationToken ct) { ... }
    public Task<UserInfo?> GetUserByIdAsync(string subjectId, CancellationToken ct) { ... }
    public Task<UserInfo?> FindByExternalProviderAsync(string provider, string externalId, CancellationToken ct) { ... }
    public Task<UserInfo>  AutoProvisionUserAsync(string provider, string externalId, IEnumerable<Claim> claims, CancellationToken ct) { ... }
}

// Register:
builder.Services
    .AddPulseAuth(...)
    .AddUserAuthentication<MyUserService>();

Login page

PulseAuth redirects to LoginPath (default /Account/Login) when the user is not authenticated. Your login page must sign the user in using ASP.NET Core Identity and then redirect back to the returnUrl parameter.

// Example Razor Page
public class LoginModel : PageModel
{
    public async Task<IActionResult> OnPostAsync(string returnUrl = "/")
    {
        var result = await _signInManager.PasswordSignInAsync(Input.Email, Input.Password, false, false);
        if (result.Succeeded)
            return LocalRedirect(returnUrl);

        ModelState.AddModelError(string.Empty, "Invalid login attempt.");
        return Page();
    }
}

External provider callback

After a social login, redirect the user back to the authorize endpoint:

// /Account/ExternalLoginCallback
public async Task<IActionResult> Callback(string returnUrl = "/")
{
    var info = await _signInManager.GetExternalLoginInfoAsync();
    
    // Find or auto-provision the user
    var user = await _pulseAuthUsers.FindByExternalProviderAsync(info.LoginProvider, info.ProviderKey)
            ?? await _pulseAuthUsers.AutoProvisionUserAsync(
                info.LoginProvider, info.ProviderKey, info.Principal.Claims);

    await _signInManager.SignInAsync(identityUser, isPersistent: false);
    return LocalRedirect(returnUrl);
}

💖 Support

This project is developed and maintained by Andrés Mariño. If you find this library useful, consider supporting its continued development:

  • Bitcoin (BTC): bc1p9zqgxghkjhauruhsza9n382e6kp5tpj4xtzu2csv4mypsdtdc4tqvdyg86
  • Ko-fi: Support Me

📝 License

This project is licensed under the MIT License. See the LICENSE file for details.


Made with ❤️ for the .NET community

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 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.  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

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.4 56 6/24/2026
1.2.3 93 6/21/2026
1.2.2 92 6/20/2026
1.1.0 95 6/18/2026
1.0.0 95 6/18/2026