IBeam.Identity.Services
2.17.0
dotnet add package IBeam.Identity.Services --version 2.17.0
NuGet\Install-Package IBeam.Identity.Services -Version 2.17.0
<PackageReference Include="IBeam.Identity.Services" Version="2.17.0" />
<PackageVersion Include="IBeam.Identity.Services" Version="2.17.0" />
<PackageReference Include="IBeam.Identity.Services" />
paket add IBeam.Identity.Services --version 2.17.0
#r "nuget: IBeam.Identity.Services, 2.17.0"
#:package IBeam.Identity.Services@2.17.0
#addin nuget:?package=IBeam.Identity.Services&version=2.17.0
#tool nuget:?package=IBeam.Identity.Services&version=2.17.0
IBeam.Identity.Services
AddIBeamIdentityTenantPurge supplies optional native orchestration over protected entity-family stores and a required trusted confirmed-job authority. No default customer/support caller can create native authorization. The Management bridge is a separate opt-in package; ordinary ownership/admin protection and global accounts remain unchanged. See tenant purge.
Independent owner protection is opt-in under IBeam:Identity:TenantOwnership. Native membership administration enforces separate owner and administrator invariants using a shared conditional snapshot. See tenant ownership protection for registration, sticky policy and the unsupported global-account lifecycle boundary.
IBM-0105: AddIBeamIdentityTenantAdministration registers an optional external tenant adapter over existing Identity creation/hooks and conditional rename ports. Recovery resumes lifecycle work with no customer actor, membership, default tenant or token. See docs/management/customer-tenant-administration.md.
Core identity orchestration package for OTP, password, OAuth, tokens, and tenant selection.
Narrative Introduction
This package is where identity behavior is implemented. It consumes contracts from IBeam.Identity and composes authentication workflows while delegating storage and delivery concerns to repository and communications providers.
Features and Components
- auth flow implementations:
PasswordAuthServiceOtpAuthServiceOAuthAuthService
- supporting services:
OtpServiceJwtTokenServiceTenantSelectionServiceTenantInviteServiceIdentityCommunicationAdapterPermissionAccessAuthorizer(dynamic permission map authorization)PermissionCatalogProvider(exposed permission catalog discovery)IBeamAccessControlService(roles, permissions, grants, modules, resources, and current access context)
- DI extension methods:
AddIBeamIdentityServices(IConfiguration)AddIBeamAccessControl(...)AddIBeamIdentityPermissionMappings(...)AddIBeamIdentityPermissionCatalog(...)AddIBeamIdentityAuthPasswordService()AddIBeamIdentityAuthOtpService()AddIBeamIdentityAuthOAuthService()AddIBeamAuthEvents(...)
Cross-Pattern Auth Orchestration
IBeam.Identity.Services lets one user move between auth patterns without creating duplicate users. The service layer always works against UserId after the repository resolves an auth identifier.
Supported flows:
- OTP with SMS:
StartOtpAsync(phone)thenCompleteOtpAsync(...). - OTP with email:
StartOtpAsync(email)thenCompleteOtpAsync(...). - Email/password:
StartEmailPasswordRegistrationAsync(...),CompleteEmailPasswordRegistrationAsync(...), thenPasswordLoginAsync(...). - Add email/password to an existing SMS user:
StartEmailPasswordLinkAsync(...), thenCompleteEmailPasswordLinkAsync(...). - Add SMS to an existing email user:
StartPhoneLinkAsync(...), thenCompletePhoneLinkAsync(...). - 2FA:
StartTwoFactorSetupAsync(...),CompleteTwoFactorSetupAsync(...), thenCompleteTwoFactorLoginAsync(...). - Tenant invites:
CreateInviteAsync(...),PreviewInviteAsync(...), andAcceptInviteAsync(...)for tenant-managed onboarding.
Successful OTP completion confirms the verified identity channel on the user record. Email OTP sets IdentityUser.EmailConfirmed = true; SMS OTP sets IdentityUser.PhoneConfirmed = true through the repository provider's confirmation fields.
The repository provider is responsible for fast identifier resolution. For Azure Table, this is done by an AuthIdentifiers table keyed by identifier type and normalized value.
Dependencies
- Internal packages:
IBeam.IdentityIBeam.Communications
- External packages:
Microsoft.Extensions.Configuration.AbstractionsMicrosoft.Extensions.Caching.AbstractionsMicrosoft.Extensions.HttpMicrosoft.Extensions.OptionsMicrosoft.Extensions.Options.ConfigurationExtensionsMicrosoft.Extensions.Identity.StoresSystem.IdentityModel.Tokens.Jwt
Required Configuration
IBeam:Identity:JwtIBeam:Identity:OtpIBeam:Identity:FeaturesIBeam:Identity:OAuth(when OAuth is enabled)IBeam:Identity:OAuthServer(optional; downstream OAuth clients and authorization-server policy)IBeam:Identity:Events(optional)IBeam:Identity:TenantProvisioning(optional; auth tenant creation/linking policy)IBeam:Identity:PermissionAccess(optional; JSON permission map source)IBeam:Identity:RoleManagement(optional; tenant/admin policy toggles)IBeam:Identity:AccessControl(optional; module, access-level, and default role policy configuration)
OTP Auto-Provision Toggle
IBeam:Identity:Otp:AllowAutoProvisionForUnknownUsertrue: OTP sign-in may create users for unknown destinationsfalse: unknown destinations are blocked in OTP start/complete flows
- Default when omitted:
Development:trueTest/Production:false
- Environment-variable override:
IBeam__Identity__Otp__AllowAutoProvisionForUnknownUser=true|false
Tenant Provisioning Policy
IBeam:Identity:TenantProvisioning:Mode controls tenant behavior after OTP, password, and OAuth authentication resolves a user.
AutoCreateTenantForNewUser: default/current behavior; creates a tenant/workspace when the authenticated user has no active membership.RequireExistingTenant: never creates or links a tenant from auth; missing membership fails with a validation error.UseDefaultTenant: usesDefaultTenantIdwhen auth requests omit tenant id.
For UseDefaultTenant, set AutoLinkUserToDefaultTenant to true when IBeam should link authenticated users to the configured tenant automatically. Optional AutoLinkRoleNames are granted during that link.
Configuration example for a single-tenant deployment:
{
"IBeam": {
"Identity": {
"TenantProvisioning": {
"Mode": "UseDefaultTenant",
"DefaultTenantId": "225925cc-995e-4584-a63b-4f2cb4f38f6f",
"AutoLinkUserToDefaultTenant": true,
"AutoLinkRoleNames": [ "Member" ]
}
}
}
}
Configuration example for strict membership-only auth:
{
"IBeam": {
"Identity": {
"TenantProvisioning": {
"Mode": "RequireExistingTenant",
"DefaultTenantId": "225925cc-995e-4584-a63b-4f2cb4f38f6f"
}
}
}
}
Code Samples
SMS OTP first, email/password later
var otp = await otpAuth.StartOtpAsync("16145551212", ct: ct);
var signedIn = await otpAuth.CompleteOtpAsync(
otp.ChallengeId,
codeFromSms,
"16145551212",
displayName: "Adam",
ct);
var userIdClaim = signedIn.Token!.Claims.First(c => c.Type == "uid").Value;
Guid userId = Guid.Parse(userIdClaim);
await passwordAuth.StartEmailPasswordLinkAsync(
userId,
"adam@test.com",
resetUrlBase: "https://app.example.com/finish-email-link",
ct: ct);
await passwordAuth.CompleteEmailPasswordLinkAsync(
userId,
"adam@test.com",
challengeId,
verificationToken,
"new secure password",
ct);
Email user adds SMS
var challenge = await passwordAuth.StartPhoneLinkAsync(userId, "16145551212", ct);
await passwordAuth.CompletePhoneLinkAsync(
userId,
"16145551212",
challenge.ChallengeId,
codeFromSms,
ct);
Single-tenant OTP with configured tenant
With Mode = UseDefaultTenant, an omitted OTP tenant id resolves to DefaultTenantId. The service also stores the effective tenant id on the OTP challenge.
var otp = await otpAuth.StartOtpAsync("+16142649686", ct: ct);
var result = await otpAuth.CompleteOtpAsync(
otp.ChallengeId,
codeFromSms,
"16142649686",
displayName: "Care Team User",
ct);
If AutoLinkUserToDefaultTenant is false and the user is not already linked to DefaultTenantId, completion fails with an IdentityValidationException.
Tenant invite onboarding
TenantInviteService handles tenant-preserving invitations without leaking whether the destination already belongs to an identity user. It sends an invite link, stores only a token hash, and on acceptance links the resolved user to the invite tenant.
var invite = await tenantInvites.CreateInviteAsync(
tenantId,
new TenantInviteCreateRequest(
DestinationType: TenantInviteDestinationTypes.Sms,
PhoneNumber: "+16145551212",
DisplayName: "Care Coordinator",
RoleNames: ["Member"],
SetAsDefaultTenant: true),
invitedByUserId,
ct);
var accepted = await tenantInvites.AcceptInviteAsync(
new TenantInviteAcceptRequest(
InviteToken: invite.InviteToken,
Mode: TenantInviteAcceptModes.Otp,
ChallengeId: challengeId,
Code: codeFromSms),
authenticatedUserId: null,
ct);
Acceptance ensures tenant membership, applies role ids/names, calls IIdentityUserExtensionCoordinator with Operation = "invite-accepted", applies optional IResourceAccessService grants when access-control services are registered, marks the invite redeemed, and returns a tenant token.
Code-based options configuration
builder.Services.AddIBeamIdentityServices(builder.Configuration);
builder.Services.Configure<TenantProvisioningOptions>(options =>
{
options.Mode = TenantProvisioningMode.RequireExistingTenant;
options.DefaultTenantId = Guid.Parse(builder.Configuration["Wellderly:TenantId"]!);
options.AutoLinkUserToDefaultTenant = false;
});
Access Control Examples
Register modules, permissions, and mappings
using IBeam.Identity.Models;
using IBeam.Identity.Services;
builder.Services.AddIBeamIdentityServices(builder.Configuration);
builder.Services.AddIBeamAccessControl(options =>
{
options.OwnerRoleNames.Clear();
options.OwnerRoleNames.Add("Owner");
options.AdminRoleNames.Clear();
options.AdminRoleNames.Add("Administrator");
options.AdminRoleNames.Add("Admin");
options.TenantUserManagementPermissionNames.Clear();
options.TenantUserManagementPermissionNames.Add("identity.tenantusers.manage");
options.TenantUserManagementPermissionNames.Add("identity.tenantinvites.manage");
options.Modules.Add(new AccessModuleDefinition(
Key: "work",
Label: "Work",
Description: "Work board access.",
SupportedAccessLevels: ["view", "edit", "manage"],
ImpliedByRoleNames: ["Owner", "Administrator", "Work Viewer"],
ImpliedByPermissionNames: ["work.view"]));
options.Modules.Add(new AccessModuleDefinition(
Key: "products",
Label: "Products",
Description: "Product catalog access.",
SupportedAccessLevels: ["view", "edit", "manage"],
ImpliedByRoleNames: ["Owner", "Administrator", "Product Manager"],
ImpliedByPermissionNames: ["products.view", "products.edit"]));
});
builder.Services.AddIBeamIdentityPermissionCatalog(catalog =>
{
catalog.AddPermission(
"work.view",
resource: "Work",
description: "Open the work board.",
label: "View work",
category: "Work",
moduleKey: "work",
accessLevel: "view");
catalog.AddPermission(
"products.edit",
resource: "Products",
description: "Edit product records.",
label: "Edit products",
category: "Products",
moduleKey: "products",
accessLevel: "edit");
});
builder.Services.AddIBeamIdentityPermissionMappings(mappings =>
{
mappings.AllowRolesForPermission("work.view", "Owner", "Administrator", "Work Viewer");
mappings.AllowRolesForPermission("products.edit", "Owner", "Administrator", "Product Manager");
});
Evaluate access imperatively
public sealed class WorkBoardService
{
private readonly IIBeamAccessControlService _access;
public WorkBoardService(IIBeamAccessControlService access)
{
_access = access;
}
public async Task<IReadOnlyList<WorkItemDto>> ListAsync(
ClaimsPrincipal user,
CancellationToken ct)
{
await _access.RequireModuleAccessAsync(
user,
moduleKey: "work",
minimumAccessLevel: "view",
ct);
return await LoadWorkItemsAsync(ct);
}
}
Build the current-user access context
public sealed class AccessBootstrapService
{
private readonly IIBeamAccessControlService _access;
public AccessBootstrapService(IIBeamAccessControlService access)
{
_access = access;
}
public Task<AccessContextDto> GetBootContextAsync(
ClaimsPrincipal user,
CancellationToken ct)
{
return _access.GetCurrentAccessContextAsync(user, tenantId: null, ct);
}
}
The returned AccessContextDto contains role names, role IDs, resolved permissions, module access, resource grants, and convenience capabilities such as CanManageUsers, CanManageRoles, CanManageAccess, and CanAssignOwner.
Service Operations, Auditing, And Permissions
Identity service methods that mutate authentication, tenants, roles, API credentials, grants, or sessions should remain service-bound operations. New custom service methods should be tagged with [IBeamOperation("identity.<area>.<action>")] or a more specific package operation name, and should route through IServiceOperationExecutor when policy/audit behavior is required.
Keep authorization-critical role assignment stable by preferring role IDs where available, while retaining role names for display, claims, and compatibility.
Extended Docs And Agent Guidance
- AI prompt:
.agent/prompt.md - Root implementation guide:
../.agent/implementation-guide.md - Azure Table schema inventory:
../docs/identity-azure-table-schema-inventory.md - Roles, permissions, and grants:
../docs/roles-permissions-and-grants.md - Service logging and audit:
../docs/service-logging-and-audit.md - Service operation permissions:
../docs/service-operation-permissions.md - Consuming API migration prompt:
../IBeam.AI.Enablement/examples/consuming-api-migration-prompt.md
Agents should keep auth orchestration in services and avoid putting tenant, role, OTP, or API credential rules into controllers or repositories.
Enterprise onboarding services and durable invitation recovery are documented in enterprise onboarding. Target services are opt-in; portal/HTTP integration follows in IBM-0108.
Approved tenant roles and invitation-only customer provisioning: registration and API contract. Catalog visibility uses the independent roles.read grant; no account/membership is created before customer verification.
IBM-0110 invitation resend/revoke uses exact versions, durable private delivery recovery and native acceptance claims. See invitation lifecycle.
IBM-0112 versioned tenant membership/role administration, concurrent final-administrator protection and required customer access enforcement: lifecycle contract.
IBM-0113 conditional tenant activation/deactivation, lifecycle recovery and current customer access rejection: status contract.
IBM-0123 adds optional native authoritative owner lookup and atomic transfer. See native ownership transfer for explicit policy, registration, exact versions and durable recovery; Management HTTP integration is separate.
IBM-0139 defines separate metadata-only versioned membership/role/ownership event contracts and a strict shared committed-event projector. AddIBeamIdentityMembershipEventContracts() installs the projector only; durable native emission/dispatch follows IBM-0140. Existing invitation events and authentication remain unchanged. See membership lifecycle events.
IBM-0140 adds optional native atomic membership/event intent and leased, bounded at-least-once dispatch with explicit durable receiver registration. Original actor/operation/sequence payloads are immutable; native owner/admin and purge fences remain active. Defaults install no emitter/delivery claim. See membership lifecycle events for scope, enrollment, startup, actor capture and recovery.
IBM-0141 adds optional current-native-state application projections and exact-version bounded trusted repair. Consumers supply atomic durable storage and their app purge guard; no support HTTP permission is installed. See membership projections.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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. |
-
net10.0
- IBeam.AccessControl.Services (>= 2.17.0)
- IBeam.Api (>= 2.17.0)
- IBeam.Communications (>= 2.17.0)
- IBeam.Identity (>= 2.17.0)
- IBeam.Services (>= 2.17.0)
- Microsoft.Extensions.Caching.Abstractions (>= 10.0.3)
- Microsoft.Extensions.Configuration.Abstractions (>= 10.0.3)
- Microsoft.Extensions.Http (>= 10.0.0)
- Microsoft.Extensions.Identity.Stores (>= 8.0.19)
- Microsoft.Extensions.Options (>= 10.0.3)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 10.0.3)
- System.IdentityModel.Tokens.Jwt (>= 8.16.0)
NuGet packages (6)
Showing the top 5 NuGet packages that depend on IBeam.Identity.Services:
| Package | Downloads |
|---|---|
|
IBeam.Identity.Repositories.AzureTable
IBeam modular framework components for .NET APIs and services. |
|
|
IBeam.Identity.Api
IBeam modular framework components for .NET APIs and services. |
|
|
IBeam.Identity.Repositories.EntityFramework
IBeam modular framework components for .NET APIs and services. |
|
|
IBeam.Management.Identity.Services
Optional isolated IBeam Identity integration for management hosts. |
|
|
IBeam.Management.Identity.Target.Services
Optional app-scoped customer Identity management services, separate from support Identity. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.17.0 | 187 | 10/28/2026 |
| 2.16.1 | 177 | 10/27/2026 |
| 2.16.0 | 242 | 10/20/2026 |
| 2.15.0 | 148 | 10/17/2026 |
| 2.15.0-rc.1 | 97 | 10/17/2026 |
| 2.14.0 | 228 | 9/28/2026 |
| 2.13.1 | 124 | 9/28/2026 |
| 2.13.0 | 129 | 9/25/2026 |
| 2.12.3 | 223 | 9/18/2026 |
| 2.12.2 | 216 | 9/11/2026 |
| 2.12.1 | 149 | 9/11/2026 |
| 2.12.0 | 137 | 9/10/2026 |
| 2.11.0 | 244 | 8/30/2026 |
| 2.10.1 | 178 | 8/23/2026 |
| 2.10.0 | 145 | 8/23/2026 |
| 2.9.45 | 211 | 8/10/2026 |
| 2.9.44 | 213 | 8/3/2026 |
| 2.9.43 | 166 | 7/29/2026 |
| 2.9.1 | 195 | 7/23/2026 |
| 2.9.0 | 161 | 7/21/2026 |