Guides
Run an app with no public sign-up
Map password sign-in, recovery, and account management without a public register route.
Create accounts in your own admin code. Do not map a public register route.
AddPasswordAuth always maps POST /register. There is no option to turn that route off. Compose sign-in instead.
Map sign-in without register
- Call
AddAuthEndpointsIdentity. It setsRequireConfirmedAccounttotrue, then runs your callback. - Register password sign-in, recovery, account management, and the cookie session. Do not call
AddPasswordSignUpEndpoints. - Map those four groups on one prefix. Do not call
MapPasswordSignUpEndpoints. - Invite each user from your admin code. A confirmation link confirms the email and sets no password. See Invite a user.
using AuthEndpoints;
using AuthEndpoints.Identity;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlite("Data Source=app.db"));
builder.Services.AddAuthEndpointsIdentity<AppUser, AppDbContext>(options =>
{
options.User.RequireUniqueEmail = true;
});
builder.Services.AddPasswordSignInEndpoints();
builder.Services.AddPasswordRecoveryEndpoints();
builder.Services.AddAccountManagementEndpoints();
builder.Services.AddCookieSessionEndpoints();
builder.Services.AddTransient<IEmailSender<AppUser>, QueuedIdentityEmailSender>();
var app = builder.Build();
app.UseAuthEndpoints();
var auth = app.MapGroup("/auth");
auth.MapPasswordSignInEndpoints<AppUser>(AuthEndpointsSession.Cookie);
auth.MapPasswordRecoveryEndpoints<AppUser>();
auth.MapCookieSessionEndpoints<AppUser>();
auth.MapAccountManagementEndpoints<AppUser>();
app.Run();
public class AppUser : IdentityUser { }
public class AppDbContext(DbContextOptions<AppDbContext> options) : IdentityDbContext<AppUser>(options) { }
public sealed class QueuedIdentityEmailSender : IEmailSender<AppUser>
{
public Task SendConfirmationLinkAsync(AppUser user, string email, string confirmationLink)
=> Task.CompletedTask;
public Task SendPasswordResetLinkAsync(AppUser user, string email, string resetLink)
=> Task.CompletedTask;
public Task SendPasswordResetCodeAsync(AppUser user, string email, string resetCode)
=> Task.CompletedTask;
}
POST /auth/login signs an existing user in. POST /auth/forgotPassword and POST /auth/resetPassword stay available. POST /auth/register is not mapped.
POST /auth/manage/password can set a first password after sign-in and step-up. It returns 404 when password sign-in is not mapped. This host maps password sign-in, so the route is present.
Invite a user
Create the account with no password, then send your own set-password link. GET /auth/confirmEmail confirms the email. It does not set a password.
- Call
UserManager<TUser>.CreateAsync(user)with no password. SetEmailConfirmedtotruebefore that call. An unconfirmed account cannot sign in, and it cannot reset a password. - Call
GeneratePasswordResetTokenAsync. Encode the token withWebEncoders.Base64UrlEncodeof the UTF-8 bytes.POST /auth/resetPassworddecodesresetCodethat way. - Send the encoded value to your own set-password screen. That screen posts
{ "email", "resetCode", "newPassword" }toPOST /auth/resetPassword.
var user = new AppUser { UserName = email, Email = email, EmailConfirmed = true };
await userManager.CreateAsync(user);
var token = await userManager.GeneratePasswordResetTokenAsync(user);
var resetCode = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(token));
WebEncoders is in Microsoft.AspNetCore.WebUtilities.
Leave these maps off
- External sign-in.
AutoLinkByEmaildefaults tofalse. Leaving it off does not stop user creation. External sign-in still creates an account for a verified email when no local user has that email. See External OAuth.MapExternalAccountEndpointsalone never creates a user. That linked login cannot sign the user in until you also mapMapExternalAuthProviderorMapExternalAuthEndpoints. - Email-code sign-up.
AllowSignUpdefaults tofalse. Leave itfalseif you map email-code sign-in. See Sign in with an emailed code. - Passkey register. For passkey login and management without that register route, call
AddPasskeySignInEndpoints<AppUser>()andAddPasskeyManagementEndpoints(). Do not callAddPasskeyEndpointsorAddPasskeySignUpEndpoints. MapMapSignInEndpoints<AppUser>(AuthEndpointsSession.Cookie)andMapPasskeyManagementEndpoints<AppUser>().MapPasskeySignInEndpointsalways mapsPOST /passkeys/register. Do not call it. In this recipe,MapSignInEndpointsreplacesMapPasswordSignInEndpointsandMapCookieSessionEndpoints. Do not map those two as well. See Passkeys.